From 2d174feb70ca745603988347fe6f138cac314f6d Mon Sep 17 00:00:00 2001 From: Miguel Luis Date: Tue, 22 Jun 2021 14:01:54 +0200 Subject: [PATCH] -WIP- Initial commit to update SAMR34 platform to ASF drivers and add NVM support - Created a temporary platform named SAMR34N - Added Microchip ASF drivers generated by Microchip Studio IDE - Adapted project HAL drivers to use the SAMR34 ASF drivers WARNING: Project compiles for the newly added platform. This commit has not yet been tested/validated --- .vscode/settings.json | 11 +- cmake/gdb-helper.cmake | 2 +- src/CMakeLists.txt | 11 + .../periodic-uplink-lpp/SAMR34N/main.c | 576 ++ src/boards/SAMR34N/CMakeLists.txt | 133 + src/boards/SAMR34N/board-config.h | 52 + src/boards/SAMR34N/board.c | 250 + src/boards/SAMR34N/delay-board.c | 26 + src/boards/SAMR34N/eeprom-board.c | 51 + src/boards/SAMR34N/gpio-board.c | 127 + src/boards/SAMR34N/i2c-board.c | 190 + src/boards/SAMR34N/rtc-board.c | 198 + src/boards/SAMR34N/spi-board.c | 81 + src/boards/SAMR34N/sx1276-board.c | 377 + src/boards/SAMR34N/uart-board.c | 223 + .../mcu/samr34/ASF/common/boards/board.h | 453 ++ .../services/serial/sam0_usart/usart_serial.h | 141 + .../ASF/common/services/serial/serial.h | 269 + .../mcu/samr34/ASF/common/utils/interrupt.h | 132 + .../utils/interrupt/interrupt_sam_nvic.c | 76 + .../utils/interrupt/interrupt_sam_nvic.h | 179 + .../mcu/samr34/ASF/common/utils/parts.h | 1768 ++++ .../samr34/ASF/common2/services/delay/delay.h | 91 + .../services/delay/sam0/systick_counter.c | 86 + .../services/delay/sam0/systick_counter.h | 103 + .../boards/samr34_xplained_pro/board_init.c | 80 + .../samr34_xplained_pro/samr34_xplained_pro.h | 532 ++ .../mcu/samr34/ASF/sam0/drivers/adc/adc.h | 1147 +++ .../ASF/sam0/drivers/adc/adc_callback.h | 172 + .../ASF/sam0/drivers/adc/adc_sam_l_c/adc.c | 830 ++ .../drivers/adc/adc_sam_l_c/adc_callback.c | 254 + .../drivers/adc/adc_sam_l_c/adc_feature.h | 727 ++ .../samr34/ASF/sam0/drivers/extint/extint.h | 699 ++ .../ASF/sam0/drivers/extint/extint_callback.c | 222 + .../ASF/sam0/drivers/extint/extint_callback.h | 98 + .../drivers/extint/extint_sam_l_c/extint.c | 481 ++ .../mcu/samr34/ASF/sam0/drivers/nvm/nvm.c | 1139 +++ .../mcu/samr34/ASF/sam0/drivers/nvm/nvm.h | 937 +++ .../nvm/quick_start_basic/qs_nvm_basic.h | 111 + .../mcu/samr34/ASF/sam0/drivers/port/port.c | 99 + .../mcu/samr34/ASF/sam0/drivers/port/port.h | 785 ++ .../drivers/port/quick_start/qs_port_basic.h | 98 + .../samr34/ASF/sam0/drivers/rtc/rtc_count.h | 1293 +++ .../sam0/drivers/rtc/rtc_count_interrupt.h | 80 + .../sam0/drivers/rtc/rtc_sam_l_c/rtc_count.c | 941 +++ .../rtc/rtc_sam_l_c/rtc_count_interrupt.c | 355 + .../samr34/ASF/sam0/drivers/rtc/rtc_tamper.h | 368 + .../ASF/sam0/drivers/sercom/i2c/i2c_common.h | 607 ++ .../ASF/sam0/drivers/sercom/i2c/i2c_master.h | 619 ++ .../drivers/sercom/i2c/i2c_master_interrupt.h | 204 + .../drivers/sercom/i2c/i2c_sam0/i2c_master.c | 1040 +++ .../i2c/i2c_sam0/i2c_master_interrupt.c | 752 ++ .../qs_i2c_master_basic_use.h | 108 + .../qs_i2c_master_callback.h | 123 + .../qs_i2c_master_dma.h | 164 + .../samr34/ASF/sam0/drivers/sercom/sercom.c | 280 + .../samr34/ASF/sam0/drivers/sercom/sercom.h | 108 + .../sam0/drivers/sercom/sercom_interrupt.c | 131 + .../sam0/drivers/sercom/sercom_interrupt.h | 62 + .../ASF/sam0/drivers/sercom/sercom_pinout.h | 612 ++ .../spi/quick_start_dma/qs_spi_dma_use.h | 258 + .../quick_start_master/qs_spi_master_basic.h | 126 + .../quick_start_slave/qs_spi_slave_basic.h | 116 + .../samr34/ASF/sam0/drivers/sercom/spi/spi.c | 1255 +++ .../samr34/ASF/sam0/drivers/sercom/spi/spi.h | 1800 +++++ .../usart/quick_start/qs_usart_basic_use.h | 106 + .../quick_start_callback/qs_usart_callback.h | 120 + .../usart/quick_start_dma/qs_usart_dma_use.h | 208 + .../sercom/usart/quick_start_lin/qs_lin.h | 94 + .../ASF/sam0/drivers/sercom/usart/usart.c | 806 ++ .../ASF/sam0/drivers/sercom/usart/usart.h | 1589 ++++ .../drivers/sercom/usart/usart_interrupt.c | 656 ++ .../drivers/sercom/usart/usart_interrupt.h | 167 + .../ASF/sam0/drivers/system/clock/clock.h | 43 + .../drivers/system/clock/clock_samr34/clock.c | 1018 +++ .../clock/clock_samr34/clock_config_check.h | 449 ++ .../system/clock/clock_samr34/clock_feature.h | 1479 ++++ .../drivers/system/clock/clock_samr34/gclk.c | 454 ++ .../ASF/sam0/drivers/system/clock/gclk.h | 297 + .../system/interrupt/system_interrupt.c | 207 + .../system/interrupt/system_interrupt.h | 423 + .../system_interrupt_features.h | 158 + .../ASF/sam0/drivers/system/pinmux/pinmux.c | 301 + .../ASF/sam0/drivers/system/pinmux/pinmux.h | 669 ++ .../pinmux/quick_start/qs_pinmux_basic.h | 86 + .../drivers/system/power/power_sam_l/power.h | 990 +++ .../drivers/system/reset/reset_sam_l/reset.h | 255 + .../samr34/ASF/sam0/drivers/system/system.c | 101 + .../samr34/ASF/sam0/drivers/system/system.h | 721 ++ .../mcu/samr34/ASF/sam0/drivers/tc/tc.h | 1788 ++++ .../samr34/ASF/sam0/drivers/tc/tc_interrupt.c | 189 + .../samr34/ASF/sam0/drivers/tc/tc_interrupt.h | 169 + .../ASF/sam0/drivers/tc/tc_sam_l_c/tc.c | 713 ++ .../quick_start/qs_emulator_basic.h | 94 + .../eeprom/emulator/rwwee_array/rww_eeprom.c | 1136 +++ .../eeprom/emulator/rwwee_array/rww_eeprom.h | 549 ++ .../utils/cmsis/samr34/include/component/ac.h | 586 ++ .../cmsis/samr34/include/component/adc.h | 728 ++ .../cmsis/samr34/include/component/aes.h | 325 + .../cmsis/samr34/include/component/ccl.h | 188 + .../cmsis/samr34/include/component/dac.h | 455 ++ .../cmsis/samr34/include/component/dmac.h | 1121 +++ .../cmsis/samr34/include/component/dsu.h | 629 ++ .../cmsis/samr34/include/component/eic.h | 422 + .../cmsis/samr34/include/component/evsys.h | 604 ++ .../cmsis/samr34/include/component/gclk.h | 251 + .../cmsis/samr34/include/component/mclk.h | 489 ++ .../cmsis/samr34/include/component/mtb.h | 382 + .../cmsis/samr34/include/component/nvmctrl.h | 549 ++ .../samr34/include/component/osc32kctrl.h | 284 + .../cmsis/samr34/include/component/oscctrl.h | 635 ++ .../cmsis/samr34/include/component/pac.h | 604 ++ .../utils/cmsis/samr34/include/component/pm.h | 277 + .../cmsis/samr34/include/component/port.h | 406 + .../cmsis/samr34/include/component/rstc.h | 208 + .../cmsis/samr34/include/component/rtc.h | 1414 ++++ .../cmsis/samr34/include/component/sercom.h | 1446 ++++ .../cmsis/samr34/include/component/supc.h | 600 ++ .../cmsis/samr34/include/component/tal.h | 882 ++ .../utils/cmsis/samr34/include/component/tc.h | 829 ++ .../cmsis/samr34/include/component/tcc.h | 1702 ++++ .../cmsis/samr34/include/component/trng.h | 172 + .../cmsis/samr34/include/component/usb.h | 1781 ++++ .../cmsis/samr34/include/component/wdt.h | 300 + .../utils/cmsis/samr34/include/instance/ac.h | 74 + .../utils/cmsis/samr34/include/instance/adc.h | 89 + .../utils/cmsis/samr34/include/instance/aes.h | 102 + .../utils/cmsis/samr34/include/instance/ccl.h | 58 + .../utils/cmsis/samr34/include/instance/dac.h | 78 + .../cmsis/samr34/include/instance/dmac.h | 98 + .../utils/cmsis/samr34/include/instance/dsu.h | 95 + .../utils/cmsis/samr34/include/instance/eic.h | 66 + .../cmsis/samr34/include/instance/evsys.h | 318 + .../cmsis/samr34/include/instance/gclk.h | 151 + .../cmsis/samr34/include/instance/mclk.h | 70 + .../utils/cmsis/samr34/include/instance/mtb.h | 89 + .../cmsis/samr34/include/instance/nvmctrl.h | 80 + .../samr34/include/instance/osc32kctrl.h | 57 + .../cmsis/samr34/include/instance/oscctrl.h | 81 + .../utils/cmsis/samr34/include/instance/pac.h | 74 + .../utils/cmsis/samr34/include/instance/pm.h | 57 + .../cmsis/samr34/include/instance/port.h | 155 + .../cmsis/samr34/include/instance/rstc.h | 53 + .../utils/cmsis/samr34/include/instance/rtc.h | 111 + .../cmsis/samr34/include/instance/sercom0.h | 130 + .../cmsis/samr34/include/instance/sercom1.h | 130 + .../cmsis/samr34/include/instance/sercom2.h | 130 + .../cmsis/samr34/include/instance/sercom3.h | 130 + .../cmsis/samr34/include/instance/sercom4.h | 130 + .../cmsis/samr34/include/instance/sercom5.h | 130 + .../cmsis/samr34/include/instance/supc.h | 65 + .../utils/cmsis/samr34/include/instance/tal.h | 158 + .../utils/cmsis/samr34/include/instance/tc0.h | 109 + .../utils/cmsis/samr34/include/instance/tc1.h | 109 + .../utils/cmsis/samr34/include/instance/tc2.h | 109 + .../utils/cmsis/samr34/include/instance/tc3.h | 109 + .../utils/cmsis/samr34/include/instance/tc4.h | 109 + .../cmsis/samr34/include/instance/tcc0.h | 115 + .../cmsis/samr34/include/instance/tcc1.h | 103 + .../cmsis/samr34/include/instance/tcc2.h | 99 + .../cmsis/samr34/include/instance/trng.h | 51 + .../utils/cmsis/samr34/include/instance/usb.h | 330 + .../utils/cmsis/samr34/include/instance/wdt.h | 55 + .../cmsis/samr34/include/pio/samr34j16b.h | 1041 +++ .../cmsis/samr34/include/pio/samr34j17b.h | 1041 +++ .../cmsis/samr34/include/pio/samr34j18b.h | 1041 +++ .../sam0/utils/cmsis/samr34/include/samr34.h | 48 + .../utils/cmsis/samr34/include/samr34j16b.h | 637 ++ .../utils/cmsis/samr34/include/samr34j17b.h | 637 ++ .../utils/cmsis/samr34/include/samr34j18b.h | 637 ++ .../cmsis/samr34/source/gcc/startup_samr34.c | 257 + .../utils/cmsis/samr34/source/system_samr34.c | 64 + .../utils/cmsis/samr34/source/system_samr34.h | 48 + .../mcu/samr34/ASF/sam0/utils/compiler.h | 1166 +++ .../samr34/ASF/sam0/utils/header_files/io.h | 119 + .../samr34/gcc/samr34j18b_flash.ld | 168 + .../ASF/sam0/utils/make/Makefile.sam.in | 492 ++ .../ASF/sam0/utils/preprocessor/mrecursion.h | 588 ++ .../ASF/sam0/utils/preprocessor/mrepeat.h | 328 + .../sam0/utils/preprocessor/preprocessor.h | 45 + .../ASF/sam0/utils/preprocessor/stringz.h | 74 + .../ASF/sam0/utils/preprocessor/tpaste.h | 93 + .../mcu/samr34/ASF/sam0/utils/status_codes.h | 148 + .../mcu/samr34/ASF/sam0/utils/stdio/read.c | 152 + .../utils/stdio/stdio_serial/stdio_serial.h | 140 + .../mcu/samr34/ASF/sam0/utils/stdio/write.c | 132 + .../ASF/sam0/utils/syscalls/gcc/syscalls.c | 120 + .../ASF/thirdparty/CMSIS/ATMEL-disclaimer.txt | 20 + .../CMSIS_END_USER_LICENCE_AGREEMENT.pdf | Bin 0 -> 179946 bytes .../ASF/thirdparty/CMSIS/Include/arm_math.h | 7157 +++++++++++++++++ .../thirdparty/CMSIS/Include/cmsis_compiler.h | 266 + .../ASF/thirdparty/CMSIS/Include/cmsis_gcc.h | 2085 +++++ .../thirdparty/CMSIS/Include/cmsis_version.h | 39 + .../thirdparty/CMSIS/Include/core_cm0plus.h | 1083 +++ .../ASF/thirdparty/CMSIS/Include/mpu_armv7.h | 270 + .../CMSIS/Lib/GCC/libarm_cortexM0l_math.a | Bin 0 -> 2768324 bytes .../ASF/thirdparty/CMSIS/Lib/license.txt | 28 + .../samr34/ASF/thirdparty/CMSIS/README.txt | 42 + .../wireless/addons/sio2host/uart/sio2host.c | 282 + .../wireless/addons/sio2host/uart/sio2host.h | 117 + .../wireless/lorawan/hal/inc/atomic.h | 86 + .../lorawan/hal/inc/radio_driver_hal.h | 314 + .../thirdparty/wireless/lorawan/hal/inc/sys.h | 72 + .../lorawan/hal/src/radio_driver_hal.c | 871 ++ .../thirdparty/wireless/lorawan/hal/src/sys.c | 85 + .../lorawan/services/edbg_eui/edbg_eui.c | 191 + .../lorawan/services/edbg_eui/edbg_eui.h | 94 + src/boards/mcu/samr34/asf.h | 141 + src/boards/mcu/samr34/config/conf_board.h | 57 + src/boards/mcu/samr34/config/conf_clocks.h | 192 + src/boards/mcu/samr34/config/conf_extint.h | 55 + src/boards/mcu/samr34/config/conf_rtc.h | 45 + src/boards/mcu/samr34/config/conf_rwwee.h | 42 + src/boards/mcu/samr34/config/conf_sio2host.h | 56 + src/boards/mcu/samr34/config/conf_spi.h | 45 + src/boards/spi-board.h | 2 +- src/radio/sx1276/sx1276.h | 2 +- 217 files changed, 86929 insertions(+), 6 deletions(-) create mode 100644 src/apps/LoRaMac/periodic-uplink-lpp/SAMR34N/main.c create mode 100644 src/boards/SAMR34N/CMakeLists.txt create mode 100644 src/boards/SAMR34N/board-config.h create mode 100644 src/boards/SAMR34N/board.c create mode 100644 src/boards/SAMR34N/delay-board.c create mode 100644 src/boards/SAMR34N/eeprom-board.c create mode 100644 src/boards/SAMR34N/gpio-board.c create mode 100644 src/boards/SAMR34N/i2c-board.c create mode 100644 src/boards/SAMR34N/rtc-board.c create mode 100644 src/boards/SAMR34N/spi-board.c create mode 100644 src/boards/SAMR34N/sx1276-board.c create mode 100644 src/boards/SAMR34N/uart-board.c create mode 100644 src/boards/mcu/samr34/ASF/common/boards/board.h create mode 100644 src/boards/mcu/samr34/ASF/common/services/serial/sam0_usart/usart_serial.h create mode 100644 src/boards/mcu/samr34/ASF/common/services/serial/serial.h create mode 100644 src/boards/mcu/samr34/ASF/common/utils/interrupt.h create mode 100644 src/boards/mcu/samr34/ASF/common/utils/interrupt/interrupt_sam_nvic.c create mode 100644 src/boards/mcu/samr34/ASF/common/utils/interrupt/interrupt_sam_nvic.h create mode 100644 src/boards/mcu/samr34/ASF/common/utils/parts.h create mode 100644 src/boards/mcu/samr34/ASF/common2/services/delay/delay.h create mode 100644 src/boards/mcu/samr34/ASF/common2/services/delay/sam0/systick_counter.c create mode 100644 src/boards/mcu/samr34/ASF/common2/services/delay/sam0/systick_counter.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/boards/samr34_xplained_pro/board_init.c create mode 100644 src/boards/mcu/samr34/ASF/sam0/boards/samr34_xplained_pro/samr34_xplained_pro.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/adc/adc.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/adc/adc_callback.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/adc/adc_sam_l_c/adc.c create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/adc/adc_sam_l_c/adc_callback.c create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/adc/adc_sam_l_c/adc_feature.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/extint/extint.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/extint/extint_callback.c create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/extint/extint_callback.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/extint/extint_sam_l_c/extint.c create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/nvm/nvm.c create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/nvm/nvm.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/nvm/quick_start_basic/qs_nvm_basic.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/port/port.c create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/port/port.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/port/quick_start/qs_port_basic.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/rtc/rtc_count.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/rtc/rtc_count_interrupt.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/rtc/rtc_sam_l_c/rtc_count.c create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/rtc/rtc_sam_l_c/rtc_count_interrupt.c create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/rtc/rtc_tamper.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/sercom/i2c/i2c_common.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/sercom/i2c/i2c_master.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/sercom/i2c/i2c_master_interrupt.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/sercom/i2c/i2c_sam0/i2c_master.c create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/sercom/i2c/i2c_sam0/i2c_master_interrupt.c create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/sercom/i2c/quick_start_master/qs_i2c_master_basic_use.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/sercom/i2c/quick_start_master_callback/qs_i2c_master_callback.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/sercom/i2c/quick_start_master_dma/qs_i2c_master_dma.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/sercom/sercom.c create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/sercom/sercom.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/sercom/sercom_interrupt.c create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/sercom/sercom_interrupt.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/sercom/sercom_pinout.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/sercom/spi/quick_start_dma/qs_spi_dma_use.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/sercom/spi/quick_start_master/qs_spi_master_basic.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/sercom/spi/quick_start_slave/qs_spi_slave_basic.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/sercom/spi/spi.c create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/sercom/spi/spi.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/sercom/usart/quick_start/qs_usart_basic_use.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/sercom/usart/quick_start_callback/qs_usart_callback.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/sercom/usart/quick_start_dma/qs_usart_dma_use.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/sercom/usart/quick_start_lin/qs_lin.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/sercom/usart/usart.c create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/sercom/usart/usart.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/sercom/usart/usart_interrupt.c create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/sercom/usart/usart_interrupt.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/system/clock/clock.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/system/clock/clock_samr34/clock.c create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/system/clock/clock_samr34/clock_config_check.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/system/clock/clock_samr34/clock_feature.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/system/clock/clock_samr34/gclk.c create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/system/clock/gclk.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/system/interrupt/system_interrupt.c create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/system/interrupt/system_interrupt.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/system/interrupt/system_interrupt_samr34/system_interrupt_features.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/system/pinmux/pinmux.c create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/system/pinmux/pinmux.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/system/pinmux/quick_start/qs_pinmux_basic.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/system/power/power_sam_l/power.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/system/reset/reset_sam_l/reset.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/system/system.c create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/system/system.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/tc/tc.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/tc/tc_interrupt.c create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/tc/tc_interrupt.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/drivers/tc/tc_sam_l_c/tc.c create mode 100644 src/boards/mcu/samr34/ASF/sam0/services/eeprom/emulator/rwwee_array/quick_start/qs_emulator_basic.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/services/eeprom/emulator/rwwee_array/rww_eeprom.c create mode 100644 src/boards/mcu/samr34/ASF/sam0/services/eeprom/emulator/rwwee_array/rww_eeprom.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/ac.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/adc.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/aes.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/ccl.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/dac.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/dmac.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/dsu.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/eic.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/evsys.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/gclk.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/mclk.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/mtb.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/nvmctrl.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/osc32kctrl.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/oscctrl.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/pac.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/pm.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/port.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/rstc.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/rtc.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/sercom.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/supc.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/tal.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/tc.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/tcc.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/trng.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/usb.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/wdt.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/ac.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/adc.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/aes.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/ccl.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/dac.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/dmac.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/dsu.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/eic.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/evsys.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/gclk.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/mclk.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/mtb.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/nvmctrl.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/osc32kctrl.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/oscctrl.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/pac.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/pm.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/port.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/rstc.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/rtc.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/sercom0.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/sercom1.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/sercom2.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/sercom3.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/sercom4.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/sercom5.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/supc.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/tal.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/tc0.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/tc1.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/tc2.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/tc3.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/tc4.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/tcc0.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/tcc1.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/tcc2.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/trng.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/usb.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/instance/wdt.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/pio/samr34j16b.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/pio/samr34j17b.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/pio/samr34j18b.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/samr34.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/samr34j16b.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/samr34j17b.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/samr34j18b.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/source/gcc/startup_samr34.c create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/source/system_samr34.c create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/source/system_samr34.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/compiler.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/header_files/io.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/linker_scripts/samr34/gcc/samr34j18b_flash.ld create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/make/Makefile.sam.in create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/preprocessor/mrecursion.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/preprocessor/mrepeat.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/preprocessor/preprocessor.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/preprocessor/stringz.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/preprocessor/tpaste.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/status_codes.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/stdio/read.c create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/stdio/stdio_serial/stdio_serial.h create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/stdio/write.c create mode 100644 src/boards/mcu/samr34/ASF/sam0/utils/syscalls/gcc/syscalls.c create mode 100644 src/boards/mcu/samr34/ASF/thirdparty/CMSIS/ATMEL-disclaimer.txt create mode 100644 src/boards/mcu/samr34/ASF/thirdparty/CMSIS/CMSIS_END_USER_LICENCE_AGREEMENT.pdf create mode 100644 src/boards/mcu/samr34/ASF/thirdparty/CMSIS/Include/arm_math.h create mode 100644 src/boards/mcu/samr34/ASF/thirdparty/CMSIS/Include/cmsis_compiler.h create mode 100644 src/boards/mcu/samr34/ASF/thirdparty/CMSIS/Include/cmsis_gcc.h create mode 100644 src/boards/mcu/samr34/ASF/thirdparty/CMSIS/Include/cmsis_version.h create mode 100644 src/boards/mcu/samr34/ASF/thirdparty/CMSIS/Include/core_cm0plus.h create mode 100644 src/boards/mcu/samr34/ASF/thirdparty/CMSIS/Include/mpu_armv7.h create mode 100644 src/boards/mcu/samr34/ASF/thirdparty/CMSIS/Lib/GCC/libarm_cortexM0l_math.a create mode 100644 src/boards/mcu/samr34/ASF/thirdparty/CMSIS/Lib/license.txt create mode 100644 src/boards/mcu/samr34/ASF/thirdparty/CMSIS/README.txt create mode 100644 src/boards/mcu/samr34/ASF/thirdparty/wireless/addons/sio2host/uart/sio2host.c create mode 100644 src/boards/mcu/samr34/ASF/thirdparty/wireless/addons/sio2host/uart/sio2host.h create mode 100644 src/boards/mcu/samr34/ASF/thirdparty/wireless/lorawan/hal/inc/atomic.h create mode 100644 src/boards/mcu/samr34/ASF/thirdparty/wireless/lorawan/hal/inc/radio_driver_hal.h create mode 100644 src/boards/mcu/samr34/ASF/thirdparty/wireless/lorawan/hal/inc/sys.h create mode 100644 src/boards/mcu/samr34/ASF/thirdparty/wireless/lorawan/hal/src/radio_driver_hal.c create mode 100644 src/boards/mcu/samr34/ASF/thirdparty/wireless/lorawan/hal/src/sys.c create mode 100644 src/boards/mcu/samr34/ASF/thirdparty/wireless/lorawan/services/edbg_eui/edbg_eui.c create mode 100644 src/boards/mcu/samr34/ASF/thirdparty/wireless/lorawan/services/edbg_eui/edbg_eui.h create mode 100644 src/boards/mcu/samr34/asf.h create mode 100644 src/boards/mcu/samr34/config/conf_board.h create mode 100644 src/boards/mcu/samr34/config/conf_clocks.h create mode 100644 src/boards/mcu/samr34/config/conf_extint.h create mode 100644 src/boards/mcu/samr34/config/conf_rtc.h create mode 100644 src/boards/mcu/samr34/config/conf_rwwee.h create mode 100644 src/boards/mcu/samr34/config/conf_sio2host.h create mode 100644 src/boards/mcu/samr34/config/conf_spi.h diff --git a/.vscode/settings.json b/.vscode/settings.json index df98d368c..669789647 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,14 +10,14 @@ // Linux : /usr // OSX : /usr/local // It is required to uncomment and to fill the following line. - //"TOOLCHAIN_PREFIX":"/path/to/toolchain", + "TOOLCHAIN_PREFIX":"C:/Program Files (x86)/GNU Arm Embedded Toolchain/10 2020-q4-major", // In case your OpenOCD is not installed under the default path: // Windows : C:/openocd/bin/openocd.exe // Linux : /usr/bin/openocd // OSX : /usr/local/bin/openocd // Please uncomment the following line and fill it accordingly. - //"OPENOCD_BIN":"C:/openocd/bin/openocd.exe", + "OPENOCD_BIN":"C:/openocd/bin/openocd.exe", // Specifies the path to the CMAKE toolchain file. "CMAKE_TOOLCHAIN_FILE":"cmake/toolchain-arm-none-eabi.cmake", @@ -30,6 +30,11 @@ // periodic-uplink-lpp, fuota-test-01. "SUB_PROJECT":"periodic-uplink-lpp", + // Select default LoRaWAN class for periodic-uplink-lpp sub-project + // In case `CLASS_B` or `CLASS_C` is selected the example will try to + // switch to the given class as soon as possible + "LORAWAN_DEFAULT_CLASS":"CLASS_A", + // Switch for Class B support of LoRaMac: "CLASSB_ENABLED":"ON", @@ -45,7 +50,7 @@ // Target board, the following boards are supported: // NAMote72, NucleoL073 (Default), NucleoL152, NucleoL476, SAMR34, SKiM880B, SKiM980A, SKiM881AXL, B-L072Z-LRWAN1. - "BOARD":"NucleoL073", + "BOARD":"SAMR34N", // MBED Radio shield selection. (Applies only to Nucleo platforms) // The following shields are supported: diff --git a/cmake/gdb-helper.cmake b/cmake/gdb-helper.cmake index 358773824..e68cfa336 100644 --- a/cmake/gdb-helper.cmake +++ b/cmake/gdb-helper.cmake @@ -91,7 +91,7 @@ function(generate_vscode_launch_openocd TARGET) elseif(BOARD STREQUAL SKiM881AXL) set(OPENOCD_INTERFACE stlink-v2.cfg) set(OPENOCD_TARGET stm32l0.cfg) - elseif(BOARD STREQUAL SAMR34) + elseif(BOARD STREQUAL SAMR34 OR BOARD STREQUAL SAMR34N) set(OPENOCD_INTERFACE cmsis-dap.cfg) set(OPENOCD_TARGET at91samdXX.cfg) endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b9289eaac..dd18b69e3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -140,6 +140,17 @@ elseif(BOARD STREQUAL SAMR34) # Configure radio set(RADIO sx1276 CACHE INTERNAL "Radio sx1276 selected") +elseif(BOARD STREQUAL SAMR34N) + # Configure toolchain for SAMR34 + set(LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/boards/mcu/samr34/ASF/sam0/utils/linker_scripts/samr34/gcc/samr34j18b_flash.ld) + include(samr34) + + # Build platform specific board implementation + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/boards/SAMR34N) + + # Configure radio + set(RADIO sx1276 CACHE INTERNAL "Radio sx1276 selected") + elseif(BOARD STREQUAL SKiM880B) # Configure toolchain for SKiM881AXL set(LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/boards/SKiM880B/cmsis/arm-gcc/stm32l151xba_flash.ld) diff --git a/src/apps/LoRaMac/periodic-uplink-lpp/SAMR34N/main.c b/src/apps/LoRaMac/periodic-uplink-lpp/SAMR34N/main.c new file mode 100644 index 000000000..09b0b3388 --- /dev/null +++ b/src/apps/LoRaMac/periodic-uplink-lpp/SAMR34N/main.c @@ -0,0 +1,576 @@ +/*! + * \file main.c + * + * \brief Performs a periodic uplink + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013-2018 Semtech + * + * \endcode + * + * \author Miguel Luis ( Semtech ) + */ + +/*! \file periodic-uplink/SAMR34/main.c */ + +#include +#include "../firmwareVersion.h" +#include "../../common/githubVersion.h" +#include "utilities.h" +#include "board.h" +#include "gpio.h" +#include "uart.h" +#include "RegionCommon.h" + +#include "cli.h" +#include "Commissioning.h" +#include "LmHandler.h" +#include "LmhpCompliance.h" +#include "CayenneLpp.h" +#include "LmHandlerMsgDisplay.h" + +#ifndef ACTIVE_REGION + +#warning "No active region defined, LORAMAC_REGION_EU868 will be used as default." + +#define ACTIVE_REGION LORAMAC_REGION_EU868 + +#endif + +/*! + * LoRaWAN default end-device class + */ +#ifndef LORAWAN_DEFAULT_CLASS +#define LORAWAN_DEFAULT_CLASS CLASS_A +#endif + +/*! + * Defines the application data transmission duty cycle. 5s, value in [ms]. + */ +#define APP_TX_DUTYCYCLE 5000 + +/*! + * Defines a random delay for application data transmission duty cycle. 1s, + * value in [ms]. + */ +#define APP_TX_DUTYCYCLE_RND 1000 + +/*! + * LoRaWAN Adaptive Data Rate + * + * \remark Please note that when ADR is enabled the end-device should be static + */ +#define LORAWAN_ADR_STATE LORAMAC_HANDLER_ADR_ON + +/*! + * Default datarate + * + * \remark Please note that LORAWAN_DEFAULT_DATARATE is used only when ADR is disabled + */ +#define LORAWAN_DEFAULT_DATARATE DR_0 + +/*! + * LoRaWAN confirmed messages + */ +#define LORAWAN_DEFAULT_CONFIRMED_MSG_STATE LORAMAC_HANDLER_UNCONFIRMED_MSG + +/*! + * User application data buffer size + */ +#define LORAWAN_APP_DATA_BUFFER_MAX_SIZE 242 + +/*! + * LoRaWAN ETSI duty cycle control enable/disable + * + * \remark Please note that ETSI mandates duty cycled transmissions. Use only for test purposes + */ +#define LORAWAN_DUTYCYCLE_ON true + +/*! + * LoRaWAN application port + * @remark The allowed port range is from 1 up to 223. Other values are reserved. + */ +#define LORAWAN_APP_PORT 2 + +/*! + * + */ +typedef enum +{ + LORAMAC_HANDLER_TX_ON_TIMER, + LORAMAC_HANDLER_TX_ON_EVENT, +}LmHandlerTxEvents_t; + +/*! + * User application data + */ +static uint8_t AppDataBuffer[LORAWAN_APP_DATA_BUFFER_MAX_SIZE]; + +/*! + * User application data structure + */ +static LmHandlerAppData_t AppData = +{ + .Buffer = AppDataBuffer, + .BufferSize = 0, + .Port = 0, +}; + +/*! + * Specifies the state of the application LED + */ +static bool AppLedStateOn = false; + +/*! + * Timer to handle the application data transmission duty cycle + */ +static TimerEvent_t TxTimer; + +/*! + * Timer to handle the state of LED1 + */ +static TimerEvent_t Led1Timer; + +/*! + * Timer to handle the state of LED2 + */ +static TimerEvent_t Led2Timer; + +/*! + * Timer to handle the state of LED beacon indicator + */ +static TimerEvent_t LedBeaconTimer; + +static void OnMacProcessNotify( void ); +static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ); +static void OnNetworkParametersChange( CommissioningParams_t* params ); +static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ); +static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ); +static void OnJoinRequest( LmHandlerJoinParams_t* params ); +static void OnTxData( LmHandlerTxParams_t* params ); +static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ); +static void OnClassChange( DeviceClass_t deviceClass ); +static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ); +#if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) +static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ); +#else +static void OnSysTimeUpdate( void ); +#endif +static void PrepareTxFrame( void ); +static void StartTxProcess( LmHandlerTxEvents_t txEvent ); +static void UplinkProcess( void ); + +static void OnTxPeriodicityChanged( uint32_t periodicity ); +static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ); +static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ); + +/*! + * Function executed on TxTimer event + */ +static void OnTxTimerEvent( void* context ); + +/*! + * Function executed on Led 1 Timeout event + */ +static void OnLed1TimerEvent( void* context ); + +/*! + * Function executed on Led 2 Timeout event + */ +static void OnLed2TimerEvent( void* context ); + +/*! + * \brief Function executed on Beacon timer Timeout event + */ +static void OnLedBeaconTimerEvent( void* context ); + +static LmHandlerCallbacks_t LmHandlerCallbacks = +{ + .GetBatteryLevel = BoardGetBatteryLevel, + .GetTemperature = NULL, + .GetRandomSeed = BoardGetRandomSeed, + .OnMacProcess = OnMacProcessNotify, + .OnNvmDataChange = OnNvmDataChange, + .OnNetworkParametersChange = OnNetworkParametersChange, + .OnMacMcpsRequest = OnMacMcpsRequest, + .OnMacMlmeRequest = OnMacMlmeRequest, + .OnJoinRequest = OnJoinRequest, + .OnTxData = OnTxData, + .OnRxData = OnRxData, + .OnClassChange= OnClassChange, + .OnBeaconStatusChange = OnBeaconStatusChange, + .OnSysTimeUpdate = OnSysTimeUpdate, +}; + +static LmHandlerParams_t LmHandlerParams = +{ + .Region = ACTIVE_REGION, + .AdrEnable = LORAWAN_ADR_STATE, + .IsTxConfirmed = LORAWAN_DEFAULT_CONFIRMED_MSG_STATE, + .TxDatarate = LORAWAN_DEFAULT_DATARATE, + .PublicNetworkEnable = LORAWAN_PUBLIC_NETWORK, + .DutyCycleEnabled = LORAWAN_DUTYCYCLE_ON, + .DataBufferMaxSize = LORAWAN_APP_DATA_BUFFER_MAX_SIZE, + .DataBuffer = AppDataBuffer, + .PingSlotPeriodicity = REGION_COMMON_DEFAULT_PING_SLOT_PERIODICITY, +}; + +static LmhpComplianceParams_t LmhpComplianceParams = +{ + .FwVersion.Value = FIRMWARE_VERSION, + .OnTxPeriodicityChanged = OnTxPeriodicityChanged, + .OnTxFrameCtrlChanged = OnTxFrameCtrlChanged, + .OnPingSlotPeriodicityChanged = OnPingSlotPeriodicityChanged, +}; + +/*! + * Indicates if LoRaMacProcess call is pending. + * + * \warning If variable is equal to 0 then the MCU can be set in low power mode + */ +static volatile uint8_t IsMacProcessPending = 0; + +static volatile uint8_t IsTxFramePending = 0; + +static volatile uint32_t TxPeriodicity = 0; + +/*! + * LED GPIO pins objects + */ +extern Gpio_t Led0; // Rx +extern Gpio_t Led1; // Tx + +/*! + * UART object used for command line interface handling + */ +extern Uart_t Uart; + +/*! + * Main application entry point. + */ +int main( void ) +{ + BoardInitMcu( ); + BoardInitPeriph( ); + + TimerInit( &Led1Timer, OnLed1TimerEvent ); + TimerSetValue( &Led1Timer, 25 ); + + TimerInit( &Led2Timer, OnLed2TimerEvent ); + TimerSetValue( &Led2Timer, 25 ); + + TimerInit( &LedBeaconTimer, OnLedBeaconTimerEvent ); + TimerSetValue( &LedBeaconTimer, 5000 ); + + // Initialize transmission periodicity variable + TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); + + const Version_t appVersion = { .Value = FIRMWARE_VERSION }; + const Version_t gitHubVersion = { .Value = GITHUB_VERSION }; + DisplayAppInfo( "periodic-uplink-lpp", + &appVersion, + &gitHubVersion ); + + if ( LmHandlerInit( &LmHandlerCallbacks, &LmHandlerParams ) != LORAMAC_HANDLER_SUCCESS ) + { + printf( "LoRaMac wasn't properly initialized\n" ); + // Fatal error, endless loop. + while ( 1 ) + { + } + } + + // Set system maximum tolerated rx error in milliseconds + LmHandlerSetSystemMaxRxError( 50 ); + + // The LoRa-Alliance Compliance protocol package should always be + // initialized and activated. + LmHandlerPackageRegister( PACKAGE_ID_COMPLIANCE, &LmhpComplianceParams ); + + LmHandlerJoin( ); + + StartTxProcess( LORAMAC_HANDLER_TX_ON_TIMER ); + + while( 1 ) + { + // Tick the RTC to execute callback in context of the main loop (in stead of the IRQ) + TimerProcess( ); + + // Process characters sent over the command line interface + CliProcess( &Uart ); + + // Processes the LoRaMac events + LmHandlerProcess( ); + + // Process application uplinks management + UplinkProcess( ); + + CRITICAL_SECTION_BEGIN( ); + if( IsMacProcessPending == 1 ) + { + // Clear flag and prevent MCU to go into low power modes. + IsMacProcessPending = 0; + } + else + { + // The MCU wakes up through events + BoardLowPowerHandler( ); + } + CRITICAL_SECTION_END( ); + } +} + +static void OnMacProcessNotify( void ) +{ + IsMacProcessPending = 1; +} + +static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size ) +{ + DisplayNvmDataChange( state, size ); +} + +static void OnNetworkParametersChange( CommissioningParams_t* params ) +{ + DisplayNetworkParametersUpdate( params ); +} + +static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ) +{ + DisplayMacMcpsRequestUpdate( status, mcpsReq, nextTxIn ); +} + +static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ) +{ + DisplayMacMlmeRequestUpdate( status, mlmeReq, nextTxIn ); +} + +static void OnJoinRequest( LmHandlerJoinParams_t* params ) +{ + DisplayJoinRequestUpdate( params ); + if( params->Status == LORAMAC_HANDLER_ERROR ) + { + LmHandlerJoin( ); + } + else + { + LmHandlerRequestClass( LORAWAN_DEFAULT_CLASS ); + } +} + +static void OnTxData( LmHandlerTxParams_t* params ) +{ + DisplayTxUpdate( params ); +} + +static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ) +{ + DisplayRxUpdate( appData, params ); + + switch( appData->Port ) + { + case 1: // The application LED can be controlled on port 1 or 2 + case LORAWAN_APP_PORT: + { + AppLedStateOn = appData->Buffer[0] & 0x01; + } + break; + default: + break; + } + + // Switch LED 1 ON for each received downlink + GpioWrite( &Led1, 1 ); + TimerStart( &Led2Timer ); +} + +static void OnClassChange( DeviceClass_t deviceClass ) +{ + DisplayClassUpdate( deviceClass ); + + // Inform the server as soon as possible that the end-device has switched to ClassB + LmHandlerAppData_t appData = + { + .Buffer = NULL, + .BufferSize = 0, + .Port = 0, + }; + LmHandlerSend( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG ); +} + +static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params ) +{ + switch( params->State ) + { + case LORAMAC_HANDLER_BEACON_RX: + { + TimerStart( &LedBeaconTimer ); + break; + } + case LORAMAC_HANDLER_BEACON_LOST: + case LORAMAC_HANDLER_BEACON_NRX: + { + TimerStop( &LedBeaconTimer ); + break; + } + default: + { + break; + } + } + + DisplayBeaconUpdate( params ); +} + +#if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) +static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection ) +{ + +} +#else +static void OnSysTimeUpdate( void ) +{ + +} +#endif + +/*! + * Prepares the payload of the frame and transmits it. + */ +static void PrepareTxFrame( void ) +{ + if( LmHandlerIsBusy( ) == true ) + { + return; + } + + uint8_t channel = 0; + + AppData.Port = LORAWAN_APP_PORT; + + CayenneLppReset( ); + CayenneLppAddDigitalInput( channel++, AppLedStateOn ); + CayenneLppAddAnalogInput( channel++, BoardGetBatteryLevel( ) * 100 / 254 ); + + CayenneLppCopy( AppData.Buffer ); + AppData.BufferSize = CayenneLppGetSize( ); + + if( LmHandlerSend( &AppData, LmHandlerParams.IsTxConfirmed ) == LORAMAC_HANDLER_SUCCESS ) + { + // Switch LED 1 ON + GpioWrite( &Led1, 0 ); + TimerStart( &Led1Timer ); + } +} + +static void StartTxProcess( LmHandlerTxEvents_t txEvent ) +{ + switch( txEvent ) + { + default: + // Intentional fall through + case LORAMAC_HANDLER_TX_ON_TIMER: + { + // Schedule 1st packet transmission + TimerInit( &TxTimer, OnTxTimerEvent ); + TimerSetValue( &TxTimer, TxPeriodicity ); + OnTxTimerEvent( NULL ); + } + break; + case LORAMAC_HANDLER_TX_ON_EVENT: + { + } + break; + } +} + +static void UplinkProcess( void ) +{ + uint8_t isPending = 0; + CRITICAL_SECTION_BEGIN( ); + isPending = IsTxFramePending; + IsTxFramePending = 0; + CRITICAL_SECTION_END( ); + if( isPending == 1 ) + { + PrepareTxFrame( ); + } +} + +static void OnTxPeriodicityChanged( uint32_t periodicity ) +{ + TxPeriodicity = periodicity; + + if( TxPeriodicity == 0 ) + { // Revert to application default periodicity + TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); + } + + // Update timer periodicity + TimerStop( &TxTimer ); + TimerSetValue( &TxTimer, TxPeriodicity ); + TimerStart( &TxTimer ); +} + +static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed ) +{ + LmHandlerParams.IsTxConfirmed = isTxConfirmed; +} + +static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity ) +{ + LmHandlerParams.PingSlotPeriodicity = pingSlotPeriodicity; +} + +/*! + * Function executed on TxTimer event + */ +static void OnTxTimerEvent( void* context ) +{ + TimerStop( &TxTimer ); + + IsTxFramePending = 1; + + // Schedule next transmission + TimerSetValue( &TxTimer, TxPeriodicity ); + TimerStart( &TxTimer ); +} + +/*! + * Function executed on Led 1 Timeout event + */ +static void OnLed1TimerEvent( void* context ) +{ + TimerStop( &Led1Timer ); + // Switch LED 1 OFF + GpioWrite( &Led1, 0 ); +} + +/*! + * Function executed on Led 2 Timeout event + */ +static void OnLed2TimerEvent( void* context ) +{ + TimerStop( &Led1Timer ); + // Switch LED 1 OFF + GpioWrite( &Led1, 0 ); +} + +/*! + * \brief Function executed on Beacon timer Timeout event + */ +static void OnLedBeaconTimerEvent( void* context ) +{ + GpioWrite( &Led1, 1 ); + TimerStart( &Led2Timer ); + + TimerStart( &LedBeaconTimer ); +} diff --git a/src/boards/SAMR34N/CMakeLists.txt b/src/boards/SAMR34N/CMakeLists.txt new file mode 100644 index 000000000..1874218ae --- /dev/null +++ b/src/boards/SAMR34N/CMakeLists.txt @@ -0,0 +1,133 @@ +## +## ______ _ +## / _____) _ | | +## ( (____ _____ ____ _| |_ _____ ____| |__ +## \____ \| ___ | (_ _) ___ |/ ___) _ \ +## _____) ) ____| | | || |_| ____( (___| | | | +## (______/|_____)_|_|_| \__)_____)\____)_| |_| +## (C)2013-2017 Semtech +## ___ _____ _ ___ _ _____ ___ ___ ___ ___ +## / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| +## \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| +## |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| +## embedded.connectivity.solutions.============== +## +## License: Revised BSD License, see LICENSE.TXT file included in the project +## Authors: Johannes Bruder (STACKFORCE), Miguel Luis (Semtech) and +## Marten Lootsma(TWTG) on behalf of Microchip/Atmel (c)2017 +## +project(SAMR34N) +cmake_minimum_required(VERSION 3.6) +enable_language(ASM) + +#--------------------------------------------------------------------------------------- +# Target +#--------------------------------------------------------------------------------------- + +list(APPEND ${PROJECT_NAME}_SOURCES + "${CMAKE_CURRENT_SOURCE_DIR}/board.c" + "${CMAKE_CURRENT_SOURCE_DIR}/delay-board.c" + "${CMAKE_CURRENT_SOURCE_DIR}/eeprom-board.c" + "${CMAKE_CURRENT_SOURCE_DIR}/gpio-board.c" + "${CMAKE_CURRENT_SOURCE_DIR}/rtc-board.c" + "${CMAKE_CURRENT_SOURCE_DIR}/spi-board.c" + "${CMAKE_CURRENT_SOURCE_DIR}/sx1276-board.c" + "${CMAKE_CURRENT_SOURCE_DIR}/uart-board.c" + "${CMAKE_CURRENT_SOURCE_DIR}/i2c-board.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/utilities.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/sercom/i2c/i2c_sam0/i2c_master.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/sercom/i2c/i2c_sam0/i2c_master_interrupt.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/common2/services/delay/sam0/systick_counter.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/common/utils/interrupt/interrupt_sam_nvic.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/boards/samr34_xplained_pro/board_init.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/adc/adc_sam_l_c/adc.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/adc/adc_sam_l_c/adc_callback.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/extint/extint_callback.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/extint/extint_sam_l_c/extint.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/nvm/nvm.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/port/port.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/rtc/rtc_sam_l_c/rtc_count.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/rtc/rtc_sam_l_c/rtc_count_interrupt.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/sercom/sercom.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/sercom/sercom_interrupt.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/sercom/spi/spi.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/sercom/usart/usart.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/sercom/usart/usart_interrupt.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/system/clock/clock_samr34/clock.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/system/clock/clock_samr34/gclk.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/system/interrupt/system_interrupt.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/system/pinmux/pinmux.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/system/system.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/tc/tc_interrupt.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/tc/tc_sam_l_c/tc.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/services/eeprom/emulator/rwwee_array/rww_eeprom.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/utils/cmsis/samr34/source/gcc/startup_samr34.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/utils/cmsis/samr34/source/system_samr34.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/utils/stdio/read.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/utils/stdio/write.c" + "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/utils/syscalls/gcc/syscalls.c" +) + +add_library(${PROJECT_NAME} OBJECT EXCLUDE_FROM_ALL ${${PROJECT_NAME}_SOURCES}) + +target_compile_definitions(${PROJECT_NAME} PUBLIC -D__SAMR34J18B__ -DARM_MATH_CM0PLUS=true -DRTC_COUNT_ASYNC=true -DSYSTICK_MODE -DADC_CALLBACK_MODE=true -DEVENTS_INTERRUPT_HOOKS_MODE=true -DTC_ASYNC=true -D_DEBUG_=0 -DBOARD=SAMR34_XPLAINED_PRO -DEXTINT_CALLBACK_MODE=true -DUSART_CALLBACK_MODE=true -DSPI_CALLBACK_MODE=false -DEDBG_EUI_READ=0 -DI2C_MASTER_CALLBACK_MODE=true) + +# Add define if radio debug pins support is enabled +target_compile_definitions(${PROJECT_NAME} PUBLIC $<$:USE_RADIO_DEBUG>) + +# For debug builds set the symbol DEBUG +set(CMAKE_C_FLAGS_DEBUG -DDEBUG) + +target_include_directories(${PROJECT_NAME} PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34 + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/config + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/common/utils + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/common/boards + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/common/services/serial + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/common2/services/delay + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/common2/services/delay/sam0 + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/boards + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/boards/samr34_xplained_pro + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/utils + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/utils/cmsis/samr34/source + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/utils/header_files + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/utils/preprocessor + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/utils/cmsis/samr34/include + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/adc + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/adc/adc_sam_l_c + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/dma + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/events + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/events/events_sam_l_c + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/extint + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/nvm + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/port + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/sercom + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/sercom/i2c + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/sercom/i2c/i2c_sam0 + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/sercom/spi + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/sercom/usart + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/rtc + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/system + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/system/clock/clock_samr34 + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/system/clock + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/system/interrupt + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/system/interrupt/system_interrupt_samr34 + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/system/pinmux + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/system/power/power_sam_l + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/system/power + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/system/reset/reset_sam_l + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/system/reset + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/drivers/tc + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/services/eeprom/emulator/rwwee_array + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/sam0/utils/stdio/stdio_serial + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/thirdparty/CMSIS/Include + ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/samr34/ASF/thirdparty/CMSIS/Lib/GCC + $ + $ + $ + $ +) + +set_property(TARGET ${PROJECT_NAME} PROPERTY C_STANDARD 11) diff --git a/src/boards/SAMR34N/board-config.h b/src/boards/SAMR34N/board-config.h new file mode 100644 index 000000000..fa555dad7 --- /dev/null +++ b/src/boards/SAMR34N/board-config.h @@ -0,0 +1,52 @@ +/*! + * \file board-config.h + * + * \brief Board configuration + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013-2017 Semtech + * + * ___ _____ _ ___ _ _____ ___ ___ ___ ___ + * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| + * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| + * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| + * embedded.connectivity.solutions=============== + * + * \endcode + */ +#ifndef __BOARD_CONFIG_H__ +#define __BOARD_CONFIG_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "asf.h" + +/*! + * Defines the time required for the TCXO to wakeup [ms]. + */ +#define BOARD_TCXO_WAKEUP_TIME 1 + +/*! + * Board MCU pins definitions + */ + +// Debug pins definition. +#define RADIO_DBG_PIN_TX NC +#define RADIO_DBG_PIN_RX NC + +#ifdef __cplusplus +} +#endif + +#endif // __BOARD_CONFIG_H__ diff --git a/src/boards/SAMR34N/board.c b/src/boards/SAMR34N/board.c new file mode 100644 index 000000000..2931e99ae --- /dev/null +++ b/src/boards/SAMR34N/board.c @@ -0,0 +1,250 @@ +/*! + * \file board.c + * + * \brief Target board general functions implementation + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013-2017 Semtech + * + * \endcode + */ +#include "asf.h" + +#include "utilities.h" + +#include "board-config.h" +#include "delay-board.h" +#include "gpio.h" +#include "adc.h" +#include "spi.h" +#include "i2c.h" +#include "uart.h" +#include "timer.h" +#include "gps.h" +#include "rtc-board.h" +#include "sx1276-board.h" +#include "../board.h" + +/* + * MCU objects + */ +Gpio_t Led0; +Gpio_t Led1; +Gpio_t Button; +Uart_t Uart; +I2c_t I2c; + +/*! + * Flag to indicate if the MCU is Initialized + */ +static bool McuInitialized = false; + +void BoardCriticalSectionBegin( uint32_t* mask ) +{ + *mask = cpu_irq_save( ); +} + +void BoardCriticalSectionEnd( uint32_t* mask ) +{ + cpu_irq_restore( *mask ); +} + +void BoardInitPeriph( void ) +{ +} + +#include +#include "delay.h" + +void BoardInitMcu( void ) +{ + /* Initialize clock system */ + system_init( ); + + delay_init( ); + + GpioInit( &Led0, LED_0_PIN, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, LED_0_INACTIVE ); + GpioInit( &Led1, LED_1_PIN, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, LED_1_INACTIVE ); + GpioInit( &Button, BUTTON_0_PIN, PIN_INPUT, PIN_PUSH_PULL, PIN_PULL_UP, BUTTON_0_INACTIVE ); + + cpu_irq_enable( ); + // RtcInit( ); + + // Uart is fully initialized inside UartInit function + UartInit( &Uart, UART_1, NC, NC ); + // This function call has no effect on UART configuration. See \ref UartInit implmentation + UartConfig( &Uart, RX_TX, 921600, UART_8_BIT, UART_1_STOP_BIT, NO_PARITY, NO_FLOW_CTRL ); + + // SPI is fully initialized inside SpiInit function + // SpiInit( &SX1276.Spi, SPI_1, NC, NC, NC, NC ); + + // Radio IO initialization + SX1276IoInit( ); + SX1276IoDbgInit( ); + SX1276IoTcxoInit( ); + + // I2C is fully initialized inside I2cInit function + // I2cInit( &I2c, I2C_1, NC, NC ); + + // Setup EEPROM emulator service + enum status_code error_code = rww_eeprom_emulator_init( ); + + if( error_code == STATUS_ERR_NO_MEMORY ) + { + while( true ) + { + /* No EEPROM section has been set in the device's fuses */ + } + } + else if( error_code != STATUS_OK ) + { + /* Erase the emulated EEPROM memory (assume it is unformatted or + * irrecoverably corrupt) */ + rww_eeprom_emulator_erase_memory( ); + rww_eeprom_emulator_init( ); + } + + McuInitialized = true; + + uint8_t buffer[256]; + uint16_t nb_bytes_read = 0; + + printf( "Hello world\n" ); + while( 1 ) + { + if( UartGetBuffer( &Uart, buffer, 256, &nb_bytes_read ) == 0 ) + { + GpioToggle( &Led0 ); + while( UartPutBuffer( &Uart, buffer, nb_bytes_read ) != 0 ) + { + }; + } + } +} + +void BoardResetMcu( void ) +{ + rww_eeprom_emulator_commit_page_buffer( ); + + CRITICAL_SECTION_BEGIN( ); + + // Restart system + NVIC_SystemReset( ); +} + +void BoardDeInitMcu( void ) +{ + SpiDeInit( &SX1276.Spi ); +} + +uint32_t BoardGetRandomSeed( void ) +{ + return 0; +} + +void BoardGetUniqueId( uint8_t* id ) +{ + // We don't have an ID, so use the one from Commissioning.h +} + +uint8_t BoardGetBatteryLevel( void ) +{ + return 0; // Battery level [0: node is connected to an external power source ... +} + +uint8_t GetBoardPowerSource( void ) +{ + return USB_POWER; +} + +void BoardLowPowerHandler( void ) +{ +} + +#if !defined( __CC_ARM ) + +/* + * Function to be used by stdout for printf etc + */ +int _write( int fd, const void* buf, size_t count ) +{ + while( UartPutBuffer( &Uart, ( uint8_t* ) buf, ( uint16_t ) count ) != 0 ) + { + }; + return count; +} + +/* + * Function to be used by stdin for scanf etc + */ +int _read( int fd, const void* buf, size_t count ) +{ + size_t bytesRead = 0; + while( UartGetBuffer( &Uart, ( uint8_t* ) buf, count, ( uint16_t* ) &bytesRead ) != 0 ) + { + }; + // Echo back the character + while( UartPutBuffer( &Uart, ( uint8_t* ) buf, ( uint16_t ) bytesRead ) != 0 ) + { + }; + return bytesRead; +} + +#else + +#include + +// Keil compiler +int fputc( int c, FILE* stream ) +{ + while( UartPutChar( &Uart, ( uint8_t ) c ) != 0 ) + ; + return c; +} + +int fgetc( FILE* stream ) +{ + uint8_t c = 0; + while( UartGetChar( &Uart, &c ) != 0 ) + ; + // Echo back the character + while( UartPutChar( &Uart, c ) != 0 ) + ; + return ( int ) c; +} + +#endif + +#ifdef USE_FULL_ASSERT + +#include + +/* + * Function Name : assert_failed + * Description : Reports the name of the source file and the source line number + * where the assert_param error has occurred. + * Input : - file: pointer to the source file name + * - line: assert_param error line source number + * Output : None + * Return : None + */ +void assert_failed( uint8_t* file, uint32_t line ) +{ + /* User can add his own implementation to report the file name and line number, + ex: printf("Wrong parameters value: file %s on line %u\n", file, line) */ + + printf( "Wrong parameters value: file %s on line %u\n", ( const char* ) file, line ); + /* Infinite loop */ + while( 1 ) + { + } +} +#endif diff --git a/src/boards/SAMR34N/delay-board.c b/src/boards/SAMR34N/delay-board.c new file mode 100644 index 000000000..617a99c82 --- /dev/null +++ b/src/boards/SAMR34N/delay-board.c @@ -0,0 +1,26 @@ +/*! + * \file delay-board.c + * + * \brief Target board delay implementation + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013-2017 Semtech + * + * \endcode + */ +#include "asf.h" + +#include "delay-board.h" + +void DelayMsMcu( uint32_t ms ) +{ + delay_ms( ms ); +} diff --git a/src/boards/SAMR34N/eeprom-board.c b/src/boards/SAMR34N/eeprom-board.c new file mode 100644 index 000000000..3ce7d037a --- /dev/null +++ b/src/boards/SAMR34N/eeprom-board.c @@ -0,0 +1,51 @@ +/*! + * \file eeprom-board.c + * + * \brief Target board EEPROM driver implementation + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013-2017 Semtech + * + * \endcode + * + * \author Miguel Luis ( Semtech ) + * + * \author Gregory Cristian ( Semtech ) + */ +#include "asf.h" + +#include "utilities.h" +#include "eeprom-board.h" + +LmnStatus_t EepromMcuWriteBuffer( uint16_t addr, uint8_t *buffer, uint16_t size ) +{ + return ( rww_eeprom_emulator_write_buffer( addr, buffer, size ) == STATUS_OK ) ? LMN_STATUS_OK : LMN_STATUS_ERROR; +} + +LmnStatus_t EepromMcuReadBuffer( uint16_t addr, uint8_t *buffer, uint16_t size ) +{ + return ( rww_eeprom_emulator_read_buffer( addr, buffer, size ) == STATUS_OK ) ? LMN_STATUS_OK : LMN_STATUS_ERROR; +} + +void EepromMcuSetDeviceAddr( uint8_t addr ) +{ + while( 1 ) + { + } +} + +LmnStatus_t EepromMcuGetDeviceAddr( void ) +{ + while( 1 ) + { + } +// return 0; +} diff --git a/src/boards/SAMR34N/gpio-board.c b/src/boards/SAMR34N/gpio-board.c new file mode 100644 index 000000000..3297b719f --- /dev/null +++ b/src/boards/SAMR34N/gpio-board.c @@ -0,0 +1,127 @@ +/*! + * \file gpio-board.c + * + * \brief Target board GPIO driver implementation + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013-2017 Semtech + * + * \endcode + */ +#include "asf.h" + +#include "board-config.h" +#include "gpio-board.h" + +void GpioMcuInit( Gpio_t* obj, PinNames pin, PinModes mode, PinConfigs config, PinTypes type, uint32_t value ) +{ + struct port_config pin_conf; + + obj->pin = pin; + + if( pin == NC ) + { + return; + } + + port_get_config_defaults( &pin_conf ); + + if( ( mode == PIN_INPUT ) || ( mode == PIN_ANALOGIC ) ) + { + pin_conf.direction = PORT_PIN_DIR_INPUT; + pin_conf.input_pull = ( enum port_pin_pull ) type; + } + else if( mode == PIN_ALTERNATE_FCT ) + { + // assert_param( LMN_STATUS_ERROR ); + while( 1 ) + ; + } + else // mode output + { + pin_conf.direction = PORT_PIN_DIR_OUTPUT; + } + port_pin_set_config( obj->pin, &pin_conf ); + + // Sets initial output value + if( mode == PIN_OUTPUT ) + { + port_pin_set_output_level( obj->pin, ( value != 0 ) ? true : false ); + } +} + +void GpioMcuSetContext( Gpio_t* obj, void* context ) +{ + obj->Context = context; +} + +void GpioMcuSetInterrupt( Gpio_t* obj, IrqModes irqMode, IrqPriorities irqPriority, GpioIrqHandler* irqHandler ) +{ + // assert_param( LMN_STATUS_ERROR ); + while( 1 ) + ; +} + +void GpioMcuRemoveInterrupt( Gpio_t* obj ) +{ + // assert_param( LMN_STATUS_ERROR ); + while( 1 ) + ; +} + +void GpioMcuWrite( Gpio_t* obj, uint32_t value ) +{ + if( obj == NULL ) + { + // assert_param( LMN_STATUS_ERROR ); + while( 1 ) + ; + } + // Check if pin is not connected + if( obj->pin == NC ) + { + return; + } + port_pin_set_output_level( obj->pin, ( value != 0 ) ? true : false ); +} + +void GpioMcuToggle( Gpio_t* obj ) +{ + if( obj == NULL ) + { + // assert_param( LMN_STATUS_ERROR ); + while( 1 ) + ; + } + + // Check if pin is not connected + if( obj->pin == NC ) + { + return; + } + port_pin_toggle_output_level( obj->pin ); +} + +uint32_t GpioMcuRead( Gpio_t* obj ) +{ + if( obj == NULL ) + { + // assert_param( LMN_STATUS_ERROR ); + while( 1 ) + ; + } + // Check if pin is not connected + if( obj->pin == NC ) + { + return 0; + } + return ( port_pin_get_output_level( obj->pin ) == true ) ? 1 : 0; +} diff --git a/src/boards/SAMR34N/i2c-board.c b/src/boards/SAMR34N/i2c-board.c new file mode 100644 index 000000000..4e139fb7b --- /dev/null +++ b/src/boards/SAMR34N/i2c-board.c @@ -0,0 +1,190 @@ +/*! + * \file i2c-board.c + * + * \brief Target board I2C driver implementation + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013-2017 Semtech + * + * \endcode + */ +#include "asf.h" + +#include "utilities.h" +#include "board-config.h" +#include "i2c-board.h" + +static struct i2c_master_module i2c_master_instance; + +void I2cMcuInit( I2c_t* obj, I2cId_t i2cId, PinNames scl, PinNames sda ) +{ + obj->I2cId = i2cId; + + /* init i2c master in full speed mode*/ + struct i2c_master_config config_i2c; + + i2c_master_get_config_defaults( &config_i2c ); + + config_i2c.buffer_timeout = 10000; + config_i2c.baud_rate = I2C_MASTER_BAUD_RATE_400KHZ; + + /* Change pins */ + config_i2c.pinmux_pad0 = PINMUX_PA16C_SERCOM1_PAD0; + config_i2c.pinmux_pad1 = PINMUX_PA17C_SERCOM1_PAD1; + + /* Initialize and enable device with config */ + i2c_master_disable( &i2c_master_instance ); + + i2c_master_init( &i2c_master_instance, SERCOM1, &config_i2c ); + + i2c_master_enable( &i2c_master_instance ); +} + +void I2cMcuDeInit( I2c_t* obj ) +{ + // Left empty +} + +void I2cMcuFormat( I2c_t* obj, I2cMode mode, I2cDutyCycle dutyCycle, bool I2cAckEnable, I2cAckAddrMode AckAddrMode, + uint32_t I2cFrequency ) +{ + // configured via i2c_master.h defaults +} + +LmnStatus_t I2cMcuWriteBuffer( I2c_t* obj, uint8_t deviceAddr, uint8_t* buffer, uint16_t size ) +{ + uint32_t timeout_cycles = 1000; + struct i2c_master_packet master_packet = { + .address = deviceAddr, + .data_length = size, + .data = buffer, + .ten_bit_address = false, + .high_speed = false, + .hs_master_code = 0x0, + }; + + while( i2c_master_write_packet_wait( &i2c_master_instance, &master_packet ) != STATUS_OK ) + { + if( timeout_cycles-- == 0 ) + { + return LMN_STATUS_ERROR; + } + } + + if( timeout_cycles > 0 ) + { + return LMN_STATUS_OK; + } + else + { + return LMN_STATUS_ERROR; + } +} + +LmnStatus_t I2cMcuReadBuffer( I2c_t* obj, uint8_t deviceAddr, uint8_t* buffer, uint16_t size ) +{ + uint32_t timeout_cycles = 1000; + struct i2c_master_packet master_packet = { + .address = deviceAddr, + .data_length = size, + .data = buffer, + .ten_bit_address = false, + .high_speed = false, + .hs_master_code = 0x0, + }; + + timeout_cycles = 1000; + while( i2c_master_read_packet_wait( &i2c_master_instance, &master_packet ) != STATUS_OK ) + { + if( timeout_cycles-- == 0 ) + { + return LMN_STATUS_ERROR; + } + } + + if( timeout_cycles > 0 ) + { + return LMN_STATUS_OK; + } + else + { + return LMN_STATUS_ERROR; + } +} + +LmnStatus_t I2cMcuWriteMemBuffer( I2c_t* obj, uint8_t deviceAddr, uint16_t addr, uint8_t* buffer, uint16_t size ) +{ + uint8_t local_addr = ( uint8_t ) addr; + uint32_t timeout_cycles = 1000; + struct i2c_master_packet master_packet = { + .address = deviceAddr, + .data_length = 1, + .data = &local_addr, + .ten_bit_address = false, + .high_speed = false, + .hs_master_code = 0x0, + }; + + while( i2c_master_write_packet_wait_no_stop( &i2c_master_instance, &master_packet ) != STATUS_OK ) + { + if( timeout_cycles-- == 0 ) + { + return LMN_STATUS_ERROR; + } + } + + timeout_cycles = 1000; + master_packet.data_length = size; + master_packet.data = buffer; + while( i2c_master_write_packet_wait( &i2c_master_instance, &master_packet ) != STATUS_OK ) + { + if( timeout_cycles-- == 0 ) + { + return LMN_STATUS_ERROR; + } + } + return LMN_STATUS_OK; +} + +LmnStatus_t I2cMcuReadMemBuffer( I2c_t* obj, uint8_t deviceAddr, uint16_t addr, uint8_t* buffer, uint16_t size ) +{ + uint8_t local_addr = ( uint8_t ) addr; + uint32_t timeout_cycles = 1000; + + struct i2c_master_packet master_packet = { + .address = deviceAddr, + .data_length = 1, + .data = &local_addr, + .ten_bit_address = false, + .high_speed = false, + .hs_master_code = 0x0, + }; + + while( i2c_master_write_packet_wait_no_stop( &i2c_master_instance, &master_packet ) != STATUS_OK ) + { + if( timeout_cycles-- == 0 ) + { + return LMN_STATUS_ERROR; + } + } + + timeout_cycles = 1000; + master_packet.data_length = size; + master_packet.data = buffer; + while( i2c_master_read_packet_wait( &i2c_master_instance, &master_packet ) != STATUS_OK ) + { + if( timeout_cycles-- == 0 ) + { + return LMN_STATUS_ERROR; + } + } + return LMN_STATUS_OK; +} diff --git a/src/boards/SAMR34N/rtc-board.c b/src/boards/SAMR34N/rtc-board.c new file mode 100644 index 000000000..bb27d6ad0 --- /dev/null +++ b/src/boards/SAMR34N/rtc-board.c @@ -0,0 +1,198 @@ +/*! + * \file rtc-board.c + * + * \brief Target board RTC timer and low power modes management + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013-2017 Semtech + * + * \endcode + */ +#include "asf.h" + +#include "utilities.h" +#include "board-config.h" +#include "board.h" +#include "timer.h" +#include "systime.h" +#include "gpio.h" + +#include "rtc-board.h" + +#define RTC_DEBUG_ENABLE 1 +#define RTC_DEBUG_DISABLE 0 + +#define RTC_DEBUG_GPIO_STATE RTC_DEBUG_DISABLE +#define RTC_DEBUG_PRINTF_STATE RTC_DEBUG_DISABLE + +#define MIN_ALARM_DELAY 3 // in ticks + +#define COMPARE_COUNT_MAX_VALUE ( 0xFFFFFFFF ) + +#define US_TO_SLEEP_TICKS( u ) ( ( u ) * ( 0.03278f ) ) +#define SLEEP_TICKS_TO_US( s ) ( ( s ) * ( 30.5175f ) ) + +#define MS_TO_SLEEP_TICKS( m ) ( ( m ) * ( 32.769f ) ) +#define SLEEP_TICKS_TO_MS( s ) ( ( s ) * ( 0.0306f ) ) + +/*! + * RTC timer context + */ +typedef struct +{ + uint32_t Time; // Reference time + uint32_t Delay; // Reference Timeout duration +} RtcTimerContext_t; + +/*! + * \brief Indicates if the RTC is already Initialized or not + */ +static bool RtcInitialized = false; + +/*! + * Keep the value of the RTC timer when the RTC alarm is set + * Set with the \ref RtcSetTimerContext function + * Value is kept as a Reference to calculate alarm + */ +static RtcTimerContext_t RtcTimerContext; + +static struct rtc_module rtc_instance; + +void RtcInit( void ) +{ + if( RtcInitialized == false ) + { + struct rtc_count_config rtc_config; + rtc_count_get_config_defaults( &rtc_config ); + + rtc_config.prescaler = RTC_COUNT_PRESCALER_OFF; + rtc_config.enable_read_sync = true; + rtc_config.compare_values[0] = COMPARE_COUNT_MAX_VALUE; + rtc_config.compare_values[1] = COMPARE_COUNT_MAX_VALUE; + rtc_count_init( &rtc_instance, RTC, &rtc_config ); + rtc_count_set_count( &rtc_instance, 0 ); + rtc_count_register_callback( &rtc_instance, TimerIrqHandler, RTC_COUNT_CALLBACK_COMPARE_0 ); + rtc_count_enable( &rtc_instance ); + + RtcInitialized = true; + } +} + +uint32_t RtcSetTimerContext( void ) +{ + RtcTimerContext.Time = ( uint32_t ) RtcGetTimerValue( ); + return ( uint32_t ) RtcTimerContext.Time; +} + +uint32_t RtcGetTimerContext( void ) +{ + return RtcTimerContext.Time; +} + +uint32_t RtcGetMinimumTimeout( void ) +{ + return ( MIN_ALARM_DELAY ); +} + +uint32_t RtcMs2Tick( TimerTime_t milliseconds ) +{ + return ( uint32_t )( ( ( ( uint64_t )milliseconds ) << 10 ) / 1000 ); +} + +TimerTime_t RtcTick2Ms( uint32_t tick ) +{ + uint32_t seconds = tick >> 10; + + tick = tick & 0x3FF; + return ( ( seconds * 1000 ) + ( ( tick * 1000 ) >> 10 ) ); +} + +void RtcDelayMs( TimerTime_t milliseconds ) +{ + uint32_t delayTicks = 0; + uint32_t refTicks = RtcGetTimerValue( ); + + delayTicks = RtcMs2Tick( milliseconds ); + + // Wait delay ms + while( ( ( RtcGetTimerValue( ) - refTicks ) ) < delayTicks ) + { + __NOP( ); + } +} + +void RtcSetAlarm( uint32_t timeout ) +{ + RtcStartAlarm( timeout ); +} + +void RtcStopAlarm( void ) +{ + rtc_count_disable_callback( &rtc_instance, RTC_COUNT_CALLBACK_COMPARE_0 ); +} + +void RtcStartAlarm( uint32_t timeout ) +{ + // rtc_count_set_count(&rtc_instance, 0); + rtc_count_set_compare( &rtc_instance, timeout, RTC_COUNT_COMPARE_0 ); + rtc_count_enable_callback( &rtc_instance, RTC_COUNT_CALLBACK_COMPARE_0 ); +} + +uint32_t RtcGetTimerValue( void ) +{ + // return ( uint32_t )HwTimerGetTime( ); + return rtc_count_get_count( &rtc_instance ); +} + +uint32_t RtcGetTimerElapsedTime( void ) +{ + return ( uint32_t )( RtcGetTimerValue( ) - RtcTimerContext.Time ); +} + +uint32_t RtcGetCalendarTime( uint16_t* milliseconds ) +{ + uint32_t ticks = 0; + + uint32_t calendarValue = RtcGetTimerValue( ); + + uint32_t seconds = ( uint32_t ) calendarValue >> 10; + + ticks = ( uint32_t ) calendarValue & 0x3FF; + + *milliseconds = RtcTick2Ms( ticks ); + + return seconds; +} + +void RtcBkupWrite( uint32_t data0, uint32_t data1 ) +{ + CRITICAL_SECTION_BEGIN( ); + rtc_instance.hw->MODE0.GP[0].reg = data0; + rtc_instance.hw->MODE0.GP[1].reg = data1; + CRITICAL_SECTION_END( ); +} + +void RtcBkupRead( uint32_t* data0, uint32_t* data1 ) +{ + CRITICAL_SECTION_BEGIN( ); + *data0 = rtc_instance.hw->MODE0.GP[0].reg; + *data1 = ( uint32_t ) rtc_instance.hw->MODE0.GP[1].reg; + CRITICAL_SECTION_END( ); +} + +void RtcProcess( void ) +{ +} + +TimerTime_t RtcTempCompensation( TimerTime_t period, float temperature ) +{ + return period; +} diff --git a/src/boards/SAMR34N/spi-board.c b/src/boards/SAMR34N/spi-board.c new file mode 100644 index 000000000..10bc21ae1 --- /dev/null +++ b/src/boards/SAMR34N/spi-board.c @@ -0,0 +1,81 @@ +/*! + * \file spi-board.c + * + * \brief Target board SPI driver implementation + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013-2017 Semtech + * + * \endcode + */ +#include "asf.h" + +#include "utilities.h" +#include "board.h" +#include "gpio.h" +#include "spi-board.h" + +static struct spi_module master; +struct spi_slave_inst slave; + +void SpiInit( Spi_t* obj, SpiId_t spiId, PinNames mosi, PinNames miso, PinNames sclk, PinNames nss ) +{ + struct spi_config config_spi_master; + struct spi_slave_inst_config slave_dev_config; + + obj->SpiId = spiId; + + spi_slave_inst_get_config_defaults( &slave_dev_config ); + + slave_dev_config.ss_pin = nss; + spi_attach_slave( &slave, &slave_dev_config ); + + spi_get_config_defaults( &config_spi_master ); + + config_spi_master.mode_specific.master.baudrate = CONF_SPI_BAUDRATE; + config_spi_master.mux_setting = SX_RF_SPI_SERCOM_MUX_SETTING; + config_spi_master.pinmux_pad0 = SX_RF_SPI_SERCOM_PINMUX_PAD0; + config_spi_master.pinmux_pad1 = PINMUX_UNUSED; + config_spi_master.pinmux_pad2 = SX_RF_SPI_SERCOM_PINMUX_PAD2; + config_spi_master.pinmux_pad3 = SX_RF_SPI_SERCOM_PINMUX_PAD3; + + spi_init( &master, SX_RF_SPI, &config_spi_master ); + spi_enable( &master ); +} + +void SpiDeInit( Spi_t* obj ) +{ + spi_disable( &master ); +} + +uint16_t SpiInOut( Spi_t* obj, uint16_t outData ) +{ + uint16_t in_data = 0; + + spi_select_slave( &master, &slave, true ); + + /* Write the byte in the transceiver data register */ + while( !spi_is_ready_to_write( &master ) ) + ; + + spi_write( &master, outData ); + + while( !spi_is_write_complete( &master ) ) + ; + while( !spi_is_ready_to_read( &master ) ) + ; + + spi_read( &master, &in_data ); + + spi_select_slave( &master, &slave, false ); + + return in_data; +} diff --git a/src/boards/SAMR34N/sx1276-board.c b/src/boards/SAMR34N/sx1276-board.c new file mode 100644 index 000000000..337a3d3c3 --- /dev/null +++ b/src/boards/SAMR34N/sx1276-board.c @@ -0,0 +1,377 @@ +/*! + * \file sx1276-board.c + * + * \brief Target board SX1276 driver implementation + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013-2017 Semtech + * + * \endcode + */ +#include + +#include "asf.h" + +#include "board-config.h" +#include "delay-board.h" +#include "radio.h" +#include "sx1276-board.h" + +static void Dio0IrqHandler( void ); +static void Dio1IrqHandler( void ); +static void Dio2IrqHandler( void ); +static void Dio3IrqHandler( void ); + +/*! + * \brief Gets the board PA selection configuration + * + * \param [IN] channel Channel frequency in Hz + * \retval PaSelect RegPaConfig PaSelect value + */ +static uint8_t SX1276GetPaSelect( uint32_t channel ); + +/*! + * Flag used to set the RF switch control pins in low power mode when the radio is not active. + */ +static bool RadioIsActive = false; + +/*! + * Radio driver structure initialization + */ +const struct Radio_s Radio = { + SX1276Init, + SX1276GetStatus, + SX1276SetModem, + SX1276SetChannel, + SX1276IsChannelFree, + SX1276Random, + SX1276SetRxConfig, + SX1276SetTxConfig, + SX1276CheckRfFrequency, + SX1276GetTimeOnAir, + SX1276Send, + SX1276SetSleep, + SX1276SetStby, + SX1276SetRx, + SX1276StartCad, + SX1276SetTxContinuousWave, + SX1276ReadRssi, + SX1276Write, + SX1276Read, + SX1276WriteBuffer, + SX1276ReadBuffer, + SX1276SetMaxPayloadLength, + SX1276SetPublicNetwork, + SX1276GetWakeupTime, + NULL, // void ( *IrqProcess )( void ) + NULL, // void ( *RxBoosted )( uint32_t timeout ) - SX126x Only + NULL, // void ( *SetRxDutyCycle )( uint32_t rxTime, uint32_t sleepTime ) - SX126x Only +}; + +/*! + * TCXO power control pin + */ +Gpio_t tcxo_pin; + +/*! + * Antenna switch GPIO pins objects + */ +Gpio_t rfswitch_pin; + +/*! + * Debug GPIO pins objects + */ +#if defined( USE_RADIO_DEBUG ) +Gpio_t DbgPinTx; +Gpio_t DbgPinRx; +#endif + +typedef struct radio_dio_pin_s +{ + Gpio_t* pin_obj; + uint8_t pin; + struct extint_chan_conf config_extint_chan; + uint8_t channel; + extint_callback_t irq_handler; +} radio_dio_pin_t; + +static radio_dio_pin_t dio_pins[] = +{ + { + .pin_obj = &SX1276.DIO0, + .pin = DIO0_PIN, + .config_extint_chan = + { + .gpio_pin = DIO0_EIC_PIN, + .gpio_pin_mux = DIO0_EIC_MUX, + .gpio_pin_pull = EXTINT_PULL_NONE, + .detection_criteria = EXTINT_DETECT_RISING, + }, + .channel = DIO0_EIC_LINE, + .irq_handler = Dio0IrqHandler, + }, + { + .pin_obj = &SX1276.DIO1, + .pin = DIO1_PIN, + .config_extint_chan = + { + .gpio_pin = DIO1_EIC_PIN, + .gpio_pin_mux = DIO1_EIC_MUX, + .gpio_pin_pull = EXTINT_PULL_NONE, + .detection_criteria = EXTINT_DETECT_BOTH, // Must be setup to be trigged on both edges. + }, + .channel = DIO1_EIC_LINE, + .irq_handler = Dio1IrqHandler, + }, + { + .pin_obj = &SX1276.DIO2, + .pin = DIO2_PIN, + .config_extint_chan = + { + .gpio_pin = DIO2_EIC_PIN, + .gpio_pin_mux = DIO2_EIC_MUX, + .gpio_pin_pull = EXTINT_PULL_NONE, + .detection_criteria = EXTINT_DETECT_RISING, + }, + .channel = DIO2_EIC_LINE, + .irq_handler = Dio2IrqHandler, + }, + { + .pin_obj = &SX1276.DIO3, + .pin = DIO3_PIN, + .config_extint_chan = + { + .gpio_pin = DIO3_EIC_PIN, + .gpio_pin_mux = DIO3_EIC_MUX, + .gpio_pin_pull = EXTINT_PULL_NONE, + .detection_criteria = EXTINT_DETECT_RISING, + }, + .channel = DIO3_EIC_LINE, + .irq_handler = Dio3IrqHandler, + + }, +}; + +void SX1276IoInit( void ) +{ + GpioInit( &rfswitch_pin, RF_SWITCH_PIN, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 ); + + for( int i = 0; i < sizeof( dio_pins ) / sizeof( radio_dio_pin_t ); i++ ) + { + GpioInit( dio_pins[i].pin_obj, dio_pins[i].pin, PIN_INPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 ); + extint_chan_get_config_defaults( &dio_pins[3].config_extint_chan ); + extint_chan_set_config( dio_pins[i].channel, &dio_pins[3].config_extint_chan ); + } +} + +static void Dio0IrqHandler( void ) +{ + if( ( dio_pins[0].pin_obj != NULL ) && ( dio_pins[0].pin_obj->IrqHandler != NULL ) ) + { + dio_pins[0].pin_obj->IrqHandler( dio_pins[0].pin_obj->Context ); + } +} + +static void Dio1IrqHandler( void ) +{ + if( ( dio_pins[1].pin_obj != NULL ) && ( dio_pins[1].pin_obj->IrqHandler != NULL ) ) + { + dio_pins[1].pin_obj->IrqHandler( dio_pins[1].pin_obj->Context ); + } +} + +static void Dio2IrqHandler( void ) +{ + if( ( dio_pins[2].pin_obj != NULL ) && ( dio_pins[2].pin_obj->IrqHandler != NULL ) ) + { + dio_pins[2].pin_obj->IrqHandler( dio_pins[2].pin_obj->Context ); + } +} + +static void Dio3IrqHandler( void ) +{ + if( ( dio_pins[3].pin_obj != NULL ) && ( dio_pins[3].pin_obj->IrqHandler != NULL ) ) + { + dio_pins[3].pin_obj->IrqHandler( dio_pins[3].pin_obj->Context ); + } +} + +static void IoIrqInit( uint8_t index, DioIrqHandler* irqHandler ) +{ + dio_pins[index].pin_obj->IrqHandler = irqHandler; + extint_register_callback( dio_pins[index].irq_handler, dio_pins[index].channel, EXTINT_CALLBACK_TYPE_DETECT ); +} + +void SX1276IoIrqInit( DioIrqHandler** irqHandlers ) +{ + for( int8_t i = 0; i < 4; i++ ) + { + IoIrqInit( i, irqHandlers[i] ); + } +} + +void SX1276IoDeInit( void ) +{ + GpioInit( &rfswitch_pin, RF_SWITCH_PIN, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 ); +} + +void SX1276IoDbgInit( void ) +{ +#if defined( USE_RADIO_DEBUG ) + GpioInit( &DbgPinTx, RADIO_DBG_PIN_TX, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 ); + GpioInit( &DbgPinRx, RADIO_DBG_PIN_RX, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 ); +#endif +} + +void SX1276IoTcxoInit( void ) +{ + GpioInit( &tcxo_pin, TCXO_PWR_PIN, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 ); +} + +void SX1276SetBoardTcxo( uint8_t state ) +{ + GpioWrite( &tcxo_pin, state ); + DelayMsMcu( BOARD_TCXO_WAKEUP_TIME ); +} + +uint32_t SX1276GetBoardTcxoWakeupTime( void ) +{ + return BOARD_TCXO_WAKEUP_TIME; +} + +void SX1276Reset( void ) +{ + // Enables the TCXO if available on the board design + SX1276SetBoardTcxo( true ); + + // Set RESET pin to 0 + GpioInit( &SX1276.Reset, SX_RF_RESET_PIN, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 ); + + // Wait 1 ms + DelayMsMcu( 1 ); + + // Configure RESET as input + GpioInit( &SX1276.Reset, SX_RF_RESET_PIN, PIN_INPUT, PIN_PUSH_PULL, PIN_NO_PULL, 1 ); + + // Wait 6 ms + DelayMsMcu( 6 ); +} + +void SX1276SetRfTxPower( int8_t power ) +{ + uint8_t paConfig = 0; + uint8_t paDac = 0; + + paConfig = SX1276Read( REG_PACONFIG ); + paDac = SX1276Read( REG_PADAC ); + + paConfig = ( paConfig & RF_PACONFIG_PASELECT_MASK ) | SX1276GetPaSelect( SX1276.Settings.Channel ); + + if( ( paConfig & RF_PACONFIG_PASELECT_PABOOST ) == RF_PACONFIG_PASELECT_PABOOST ) + { + if( power > 17 ) + { + paDac = ( paDac & RF_PADAC_20DBM_MASK ) | RF_PADAC_20DBM_ON; + } + else + { + paDac = ( paDac & RF_PADAC_20DBM_MASK ) | RF_PADAC_20DBM_OFF; + } + if( ( paDac & RF_PADAC_20DBM_ON ) == RF_PADAC_20DBM_ON ) + { + if( power < 5 ) + { + power = 5; + } + if( power > 20 ) + { + power = 20; + } + paConfig = ( paConfig & RF_PACONFIG_OUTPUTPOWER_MASK ) | ( uint8_t )( ( uint16_t )( power - 5 ) & 0x0F ); + } + else + { + if( power < 2 ) + { + power = 2; + } + if( power > 17 ) + { + power = 17; + } + paConfig = ( paConfig & RF_PACONFIG_OUTPUTPOWER_MASK ) | ( uint8_t )( ( uint16_t )( power - 2 ) & 0x0F ); + } + } + else + { + if( power > 0 ) + { + if( power > 15 ) + { + power = 15; + } + paConfig = + ( paConfig & RF_PACONFIG_MAX_POWER_MASK & RF_PACONFIG_OUTPUTPOWER_MASK ) | ( 7 << 4 ) | ( power ); + } + else + { + if( power < -4 ) + { + power = -4; + } + paConfig = + ( paConfig & RF_PACONFIG_MAX_POWER_MASK & RF_PACONFIG_OUTPUTPOWER_MASK ) | ( 0 << 4 ) | ( power + 4 ); + } + } + SX1276Write( REG_PACONFIG, paConfig ); + SX1276Write( REG_PADAC, paDac ); +} + +static uint8_t SX1276GetPaSelect( uint32_t channel ) +{ + return RF_PACONFIG_PASELECT_PABOOST; +} + +void SX1276SetAntSwLowPower( bool status ) +{ + // Control the TCXO and Antenna switch + if( RadioIsActive != status ) + { + RadioIsActive = status; + } +} + +void SX1276SetAntSw( uint8_t opMode ) +{ +} + +bool SX1276CheckRfFrequency( uint32_t frequency ) +{ + // Implement check. Currently all frequencies are supported + return true; +} + +uint32_t SX1276GetDio1PinState( void ) +{ + return GpioRead( &SX1276.DIO1 ); +} + +#if defined( USE_RADIO_DEBUG ) +void SX1276DbgPinTxWrite( uint8_t state ) +{ + GpioWrite( &DbgPinTx, state ); +} + +void SX1276DbgPinRxWrite( uint8_t state ) +{ + GpioWrite( &DbgPinRx, state ); +} +#endif diff --git a/src/boards/SAMR34N/uart-board.c b/src/boards/SAMR34N/uart-board.c new file mode 100644 index 000000000..5bfa68bc8 --- /dev/null +++ b/src/boards/SAMR34N/uart-board.c @@ -0,0 +1,223 @@ +/*! + * \file uart-board.c + * + * \brief Target board UART driver implementation + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013-2017 Semtech + * + * \endcode + */ +#include "asf.h" + +#include "utilities.h" + +#include "board.h" +#include "uart-board.h" + +/*! + * Number of times the UartPutBuffer will try to send the buffer before + * returning ERROR + */ +#define TX_BUFFER_RETRY_COUNT 10 + +/*! + * UART FIFO buffer size + */ +#define UART_FIFO_TX_SIZE 1024 +#define UART_FIFO_RX_SIZE 1024 + +static uint8_t uart_tx_buffer[UART_FIFO_TX_SIZE]; +static uint8_t uart_rx_buffer[UART_FIFO_RX_SIZE]; + +static struct usart_module host_uart_module; +static struct usart_config host_uart_config; +static Uart_t* uart_obj; + +void UartTxIrqHandler( struct usart_module* const module ); + +void UartRxIrqHandler( struct usart_module* const module ); + +void UartMcuInit( Uart_t* obj, uint8_t uartId, PinNames tx, PinNames rx ) +{ + uart_obj = obj; + uart_obj->UartId = uartId; + + FifoInit( &uart_obj->FifoTx, uart_tx_buffer, UART_FIFO_TX_SIZE ); + FifoInit( &uart_obj->FifoRx, uart_rx_buffer, UART_FIFO_RX_SIZE ); + + usart_get_config_defaults( &host_uart_config ); + host_uart_config.baudrate = 115200; + host_uart_config.mux_setting = EDBG_CDC_SERCOM_MUX_SETTING; + host_uart_config.pinmux_pad0 = EDBG_CDC_SERCOM_PINMUX_PAD0; + host_uart_config.pinmux_pad1 = EDBG_CDC_SERCOM_PINMUX_PAD1; + host_uart_config.pinmux_pad2 = EDBG_CDC_SERCOM_PINMUX_PAD2; + host_uart_config.pinmux_pad3 = EDBG_CDC_SERCOM_PINMUX_PAD3; + stdio_serial_init( &host_uart_module, EDBG_CDC_MODULE, &host_uart_config ); + usart_enable( &host_uart_module ); + // Enable transceivers + usart_enable_transceiver( &host_uart_module, USART_TRANSCEIVER_TX ); + usart_enable_transceiver( &host_uart_module, USART_TRANSCEIVER_RX ); + + usart_register_callback( &host_uart_module, UartTxIrqHandler, USART_CALLBACK_BUFFER_TRANSMITTED ); + usart_register_callback( &host_uart_module, UartRxIrqHandler, USART_CALLBACK_BUFFER_RECEIVED ); + usart_enable_callback( &host_uart_module, USART_CALLBACK_BUFFER_TRANSMITTED ); + usart_enable_callback( &host_uart_module, USART_CALLBACK_BUFFER_RECEIVED ); +} + +void UartMcuConfig( Uart_t* obj, UartMode_t mode, uint32_t baudrate, WordLength_t wordLength, StopBits_t stopBits, + Parity_t parity, FlowCtrl_t flowCtrl ) +{ + // configured via UartMcuInit +} + +void UartMcuDeInit( Uart_t* obj ) +{ + usart_disable( &host_uart_module ); + + // Disable transceivers + usart_disable_transceiver( &host_uart_module, USART_TRANSCEIVER_TX ); + usart_disable_transceiver( &host_uart_module, USART_TRANSCEIVER_RX ); +} + +uint8_t UartMcuPutChar( Uart_t* obj, uint8_t data ) +{ + CRITICAL_SECTION_BEGIN( ); + + if( IsFifoEmpty( &obj->FifoTx ) == true ) + { + CRITICAL_SECTION_END( ); + + // Write one byte to the transmit data register + if( usart_write_buffer_job( &host_uart_module, &data, 1 ) == STATUS_OK ) + { + CRITICAL_SECTION_END( ); + return 0; + } + + return 0; // OK + } + if( IsFifoFull( &obj->FifoTx ) == false ) + { + FifoPush( &obj->FifoTx, data ); + + CRITICAL_SECTION_END( ); + return 0; // OK + } + CRITICAL_SECTION_END( ); + return 1; // Busy +} + +uint8_t UartMcuGetChar( Uart_t* obj, uint8_t* data ) +{ + CRITICAL_SECTION_BEGIN( ); + + if( IsFifoEmpty( &obj->FifoRx ) == false ) + { + *data = FifoPop( &obj->FifoRx ); + CRITICAL_SECTION_END( ); + return 0; + } + else + { + if( usart_read_buffer_job( &host_uart_module, data, 1 ) == STATUS_OK ) + { + CRITICAL_SECTION_END( ); + return 0; + } + } + CRITICAL_SECTION_END( ); + return 1; +} + +uint8_t UartMcuPutBuffer( Uart_t* obj, uint8_t* buffer, uint16_t size ) +{ + uint8_t retryCount; + uint16_t i; + + for( i = 0; i < size; i++ ) + { + retryCount = 0; + while( UartPutChar( obj, buffer[i] ) != 0 ) + { + retryCount++; + + // Exit if something goes terribly wrong + if( retryCount > TX_BUFFER_RETRY_COUNT ) + { + return 1; // Error + } + } + } + return 0; // OK +} + +uint8_t UartMcuGetBuffer( Uart_t* obj, uint8_t* buffer, uint16_t size, uint16_t* nbReadBytes ) +{ + uint16_t localSize = 0; + + while( localSize < size ) + { + if( UartGetChar( obj, buffer + localSize ) == 0 ) + { + localSize++; + } + else + { + break; + } + } + + *nbReadBytes = localSize; + + if( localSize == 0 ) + { + return 1; // Empty + } + return 0; // OK +} + +void UartTxIrqHandler( struct usart_module* const module ) +{ + uint8_t temp; + if( IsFifoEmpty( &uart_obj->FifoTx ) == false ) + { + temp = FifoPop( &uart_obj->FifoTx ); + // Write one byte to the transmit data register + usart_write_buffer_job( &host_uart_module, &temp, 1 ); + } + + if( uart_obj->IrqNotify != NULL ) + { + uart_obj->IrqNotify( UART_NOTIFY_TX ); + } +} + +void UartRxIrqHandler( struct usart_module* const module ) +{ + uint8_t temp; + + usart_read_buffer_job( &host_uart_module, &temp, 1 ); + + // Introducing critical section to avoid buffer corruption. + CRITICAL_SECTION_BEGIN( ); + if( IsFifoFull( &uart_obj->FifoRx ) == false ) + { + // Read one byte from the receive data register + FifoPush( &uart_obj->FifoRx, temp ); + } + + if( uart_obj->IrqNotify != NULL ) + { + uart_obj->IrqNotify( UART_NOTIFY_RX ); + } + CRITICAL_SECTION_END( ); +} diff --git a/src/boards/mcu/samr34/ASF/common/boards/board.h b/src/boards/mcu/samr34/ASF/common/boards/board.h new file mode 100644 index 000000000..c667b805b --- /dev/null +++ b/src/boards/mcu/samr34/ASF/common/boards/board.h @@ -0,0 +1,453 @@ +/** + * \file + * + * \brief Standard board header file. + * + * This file includes the appropriate board header file according to the + * defined board (parameter BOARD). + * + * Copyright (c) 2009-2020 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#ifndef _BOARD_H_ +#define _BOARD_H_ + +/** + * \defgroup group_common_boards Generic board support + * + * The generic board support module includes board-specific definitions + * and function prototypes, such as the board initialization function. + * + * \{ + */ + +#include "compiler.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/*! \name Base Boards + */ +//! @{ +#define EVK1100 1 //!< AT32UC3A EVK1100 board. +#define EVK1101 2 //!< AT32UC3B EVK1101 board. +#define UC3C_EK 3 //!< AT32UC3C UC3C-EK board. +#define EVK1104 4 //!< AT32UC3A3 EVK1104 board. +#define EVK1105 5 //!< AT32UC3A EVK1105 board. +#define STK600_RCUC3L0 6 //!< STK600 RCUC3L0 board. +#define UC3L_EK 7 //!< AT32UC3L-EK board. +#define XPLAIN 8 //!< ATxmega128A1 Xplain board. +#define STK600_RC064X 10 //!< ATxmega256A3 STK600 board. +#define STK600_RC100X 11 //!< ATxmega128A1 STK600 board. +#define UC3_A3_XPLAINED 13 //!< ATUC3A3 UC3-A3 Xplained board. +#define UC3_L0_XPLAINED 15 //!< ATUC3L0 UC3-L0 Xplained board. +#define STK600_RCUC3D 16 //!< STK600 RCUC3D board. +#define STK600_RCUC3C0 17 //!< STK600 RCUC3C board. +#define XMEGA_B1_XPLAINED 18 //!< ATxmega128B1 Xplained board. +#define XMEGA_A1_XPLAINED 19 //!< ATxmega128A1 Xplain-A1 board. +#define XMEGA_A1U_XPLAINED_PRO 20 //!< ATxmega128A1U XMEGA-A1U Xplained Pro board. +#define STK600_RCUC3L4 21 //!< ATUCL4 STK600 board. +#define UC3_L0_XPLAINED_BC 22 //!< ATUC3L0 UC3-L0 Xplained board controller board. +#define MEGA1284P_XPLAINED_BC 23 //!< ATmega1284P-Xplained board controller board. +#define STK600_RC044X 24 //!< STK600 with RC044X routing card board. +#define STK600_RCUC3B0 25 //!< STK600 RCUC3B0 board. +#define UC3_L0_QT600 26 //!< QT600 UC3L0 MCU board. +#define XMEGA_A3BU_XPLAINED 27 //!< ATxmega256A3BU Xplained board. +#define STK600_RC064X_LCDX 28 //!< XMEGAB3 STK600 RC064X LCDX board. +#define STK600_RC100X_LCDX 29 //!< XMEGAB1 STK600 RC100X LCDX board. +#define UC3B_BOARD_CONTROLLER 30 //!< AT32UC3B1 board controller for Atmel boards. +#define RZ600 31 //!< AT32UC3A RZ600 MCU board. +#define SAM3S_EK 32 //!< SAM3S-EK board. +#define SAM3U_EK 33 //!< SAM3U-EK board. +#define SAM3X_EK 34 //!< SAM3X-EK board. +#define SAM3N_EK 35 //!< SAM3N-EK board. +#define SAM3S_EK2 36 //!< SAM3S-EK2 board. +#define SAM4S_EK 37 //!< SAM4S-EK board. +#define STK600_RCUC3A0 38 //!< STK600 RCUC3A0 board. +#define STK600_MEGA 39 //!< STK600 MEGA board. +#define MEGA_1284P_XPLAINED 40 //!< ATmega1284P Xplained board. +#define SAM4S_XPLAINED 41 //!< SAM4S Xplained board. +#define ATXMEGA128A1_QT600 42 //!< QT600 ATXMEGA128A1 MCU board. +#define ARDUINO_DUE_X 43 //!< Arduino Due/X board. +#define STK600_RCUC3L3 44 //!< ATUCL3 STK600 board. +#define SAM4L_EK 45 //!< SAM4L-EK board. +#define STK600_MEGA_RF 46 //!< STK600 MEGA RF EVK board. +#define XMEGA_C3_XPLAINED 47 //!< ATxmega384C3 Xplained board. +#define STK600_RC032X 48 //!< STK600 with RC032X routing card board. +#define SAM4S_EK2 49 //!< SAM4S-EK2 board. +#define XMEGA_E5_XPLAINED 50 //!< ATxmega32E5 Xplained board. +#define SAM4E_EK 51 //!< SAM4E-EK board. +#define ATMEGA256RFR2_XPLAINED_PRO 52 //!< ATmega256RFR2 Xplained Pro board. +#define SAM4S_XPLAINED_PRO 53 //!< SAM4S Xplained Pro board. +#define SAM4L_XPLAINED_PRO 54 //!< SAM4L Xplained Pro board. +#define ATMEGA256RFR2_ZIGBIT 55 //!< ATmega256RFR2 zigbit. +#define XMEGA_RF233_ZIGBIT 56 //!< ATxmega256A3U with AT86RF233 Zigbit. +#define XMEGA_RF212B_ZIGBIT 57 //!< ATxmega256A3U with AT86RF212B Zigbit. +#define SAM4S_WPIR_RD 58 //!< SAM4S-WPIR-RD board. +#define SAMD20_XPLAINED_PRO 59 //!< SAM D20 Xplained Pro board. +#define SAM4L8_XPLAINED_PRO 60 //!< SAM4L8 Xplained Pro board. +#define SAM4N_XPLAINED_PRO 61 //!< SAM4N Xplained Pro board. +#define XMEGA_A3_REB_CBB 62 //!< XMEGA REB Controller Base board. +#define ATMEGARFX_RCB 63 //!< RFR2 & RFA1 RCB. +#define SAM4C_EK 64 //!< SAM4C-EK board. +#define RCB256RFR2_XPRO 65 //!< RFR2 RCB Xplained Pro board. +#define SAMG53_XPLAINED_PRO 66 //!< SAMG53 Xplained Pro board. +#define SAM4CP16BMB 67 //!< SAM4CP16BMB board. +#define SAM4E_XPLAINED_PRO 68 //!< SAM4E Xplained Pro board. +#define SAMD21_XPLAINED_PRO 69 //!< SAM D21 Xplained Pro board. +#define SAMR21_XPLAINED_PRO 70 //!< SAM R21 Xplained Pro board. +#define SAM4CMP_DB 71 //!< SAM4CMP demo board. +#define SAM4CMS_DB 72 //!< SAM4CMS demo board. +#define ATPL230AMB 73 //!< ATPL230AMB board. +#define SAMD11_XPLAINED_PRO 74 //!< SAM D11 Xplained Pro board. +#define SAMG55_XPLAINED_PRO 75 //!< SAMG55 Xplained Pro board. +#define SAML21_XPLAINED_PRO 76 //!< SAM L21 Xplained Pro board. +#define SAMD10_XPLAINED_MINI 77 //!< SAM D10 Xplained Mini board. +#define SAMDA1_XPLAINED_PRO 78 //!< SAM DA1 Xplained Pro board. +#define SAMW25_XPLAINED_PRO 79 //!< SAMW25 Xplained Pro board. +#define SAMC21_XPLAINED_PRO 80 //!< SAM C21 Xplained Pro board. +#define SAMV71_XPLAINED_ULTRA 81 //!< SAMV71 Xplained Ultra board. +#define ATMEGA328P_XPLAINED_MINI 82 //!< ATMEGA328P Xplained MINI board. +#define ATMEGA328PB_XPLAINED_MINI 83 //!< ATMEGA328PB Xplained MINI board. +#define SAMB11_XPLAINED_PRO 84 //!< SAM B11 Xplained Pro board. +#define SAME70_XPLAINED 85 //!< SAME70 Xplained board. +#define SAML22_XPLAINED_PRO 86 //!< SAM L22 Xplained Pro board. +#define SAML22_XPLAINED_PRO_B 87 //!< SAM L22 Xplained Pro board. +#define SAMR21ZLL_EK 88 //!< SAMR21ZLL-EK board. +#define ATMEGA168PB_XPLAINED_MINI 89 //!< ATMEGA168PB Xplained MINI board. +#define ATMEGA324PB_XPLAINED_PRO 90 //!< ATMEGA324PB Xplained Pro board. +#define SAMB11ZR_XPLAINED_PRO 92 //!< SAM B11 ZR Xplained Pro board. +#define SAMR30_XPLAINED_PRO 93 //!< SAM R30 Xplained Pro board. +#define SAMHA1G16A_XPLAINED_PRO 94 //!< SAM HA1G16A Xplained Pro board. +#define SAMR34_XPLAINED_PRO 95 //!< SAM R34 Xplained Pro board. +#define SIMULATOR_XMEGA_A1 97 //!< Simulator for XMEGA A1 devices. +#define AVR_SIMULATOR_UC3 98 //!< Simulator for the AVR UC3 device family. +#define USER_BOARD 99 //!< User-reserved board (if any). +#define DUMMY_BOARD 100 //!< Dummy board to support board-independent applications (e.g. bootloader). +#define SAMB11ZR_SENSOR_TAG 101 //!< SAMB11ZR sensor tag board +#define SAMR30_MODULE_XPLAINED_PRO 102 //!< SAM R30 Module Xplained Pro board. +#define SAMR21G18_MODULE 103 //!< SAMR21G18-MR210UA Module. +#define SAMR21B18_MODULE 104 //!< SAMR21B18-MZ210PA Module. +#define WLR089_XPLAINED_PRO 105 //!< WLR089_XPLAINED_PRO board. +//! @} + +/*! \name Extension Boards + */ +//! @{ +#define EXT1102 1 //!< AT32UC3B EXT1102 board +#define MC300 2 //!< AT32UC3 MC300 board +#define SENSORS_XPLAINED_INERTIAL_1 3 //!< Xplained inertial sensor board 1 +#define SENSORS_XPLAINED_INERTIAL_2 4 //!< Xplained inertial sensor board 2 +#define SENSORS_XPLAINED_PRESSURE_1 5 //!< Xplained pressure sensor board +#define SENSORS_XPLAINED_LIGHTPROX_1 6 //!< Xplained light & proximity sensor board +#define SENSORS_XPLAINED_INERTIAL_A1 7 //!< Xplained inertial sensor board "A" +#define RZ600_AT86RF231 8 //!< AT86RF231 RF board in RZ600 +#define RZ600_AT86RF230B 9 //!< AT86RF230B RF board in RZ600 +#define RZ600_AT86RF212 10 //!< AT86RF212 RF board in RZ600 +#define SENSORS_XPLAINED_BREADBOARD 11 //!< Xplained sensor development breadboard +#define SECURITY_XPLAINED 12 //!< Xplained ATSHA204 board +#define USER_EXT_BOARD 99 //!< User-reserved extension board (if any). +//! @} + +#if BOARD == EVK1100 +# include "evk1100/evk1100.h" +#elif BOARD == EVK1101 +# include "evk1101/evk1101.h" +#elif BOARD == UC3C_EK +# include "uc3c_ek/uc3c_ek.h" +#elif BOARD == EVK1104 +# include "evk1104/evk1104.h" +#elif BOARD == EVK1105 +# include "evk1105/evk1105.h" +#elif BOARD == STK600_RCUC3L0 +# include "stk600/rcuc3l0/stk600_rcuc3l0.h" +#elif BOARD == UC3L_EK +# include "uc3l_ek/uc3l_ek.h" +#elif BOARD == STK600_RCUC3L4 +# include "stk600/rcuc3l4/stk600_rcuc3l4.h" +#elif BOARD == XPLAIN +# include "xplain/xplain.h" +#elif BOARD == STK600_MEGA + /*No header-file to include*/ +#elif BOARD == STK600_MEGA_RF +# include "stk600.h" +#elif BOARD == ATMEGA256RFR2_XPLAINED_PRO +# include "atmega256rfr2_xplained_pro/atmega256rfr2_xplained_pro.h" +#elif BOARD == ATMEGA256RFR2_ZIGBIT +# include "atmega256rfr2_zigbit/atmega256rfr2_zigbit.h" +#elif BOARD == STK600_RC032X +# include "stk600/rc032x/stk600_rc032x.h" +#elif BOARD == STK600_RC044X +# include "stk600/rc044x/stk600_rc044x.h" +#elif BOARD == STK600_RC064X +# include "stk600/rc064x/stk600_rc064x.h" +#elif BOARD == STK600_RC100X +# include "stk600/rc100x/stk600_rc100x.h" +#elif BOARD == UC3_A3_XPLAINED +# include "uc3_a3_xplained/uc3_a3_xplained.h" +#elif BOARD == UC3_L0_XPLAINED +# include "uc3_l0_xplained/uc3_l0_xplained.h" +#elif BOARD == STK600_RCUC3B0 +# include "stk600/rcuc3b0/stk600_rcuc3b0.h" +#elif BOARD == STK600_RCUC3D +# include "stk600/rcuc3d/stk600_rcuc3d.h" +#elif BOARD == STK600_RCUC3C0 +# include "stk600/rcuc3c0/stk600_rcuc3c0.h" +#elif BOARD == SAMG53_XPLAINED_PRO +# include "samg53_xplained_pro/samg53_xplained_pro.h" +#elif BOARD == SAMG55_XPLAINED_PRO +# include "samg55_xplained_pro/samg55_xplained_pro.h" +#elif BOARD == XMEGA_B1_XPLAINED +# include "xmega_b1_xplained/xmega_b1_xplained.h" +#elif BOARD == STK600_RC064X_LCDX +# include "stk600/rc064x_lcdx/stk600_rc064x_lcdx.h" +#elif BOARD == STK600_RC100X_LCDX +# include "stk600/rc100x_lcdx/stk600_rc100x_lcdx.h" +#elif BOARD == XMEGA_A1_XPLAINED +# include "xmega_a1_xplained/xmega_a1_xplained.h" +#elif BOARD == XMEGA_A1U_XPLAINED_PRO +# include "xmega_a1u_xplained_pro/xmega_a1u_xplained_pro.h" +#elif BOARD == UC3_L0_XPLAINED_BC +# include "uc3_l0_xplained_bc/uc3_l0_xplained_bc.h" +#elif BOARD == SAM3S_EK +# include "sam3s_ek/sam3s_ek.h" +# include "system_sam3s.h" +#elif BOARD == SAM3S_EK2 +# include "sam3s_ek2/sam3s_ek2.h" +# include "system_sam3sd8.h" +#elif BOARD == SAM3U_EK +# include "sam3u_ek/sam3u_ek.h" +# include "system_sam3u.h" +#elif BOARD == SAM3X_EK +# include "sam3x_ek/sam3x_ek.h" +# include "system_sam3x.h" +#elif BOARD == SAM3N_EK +# include "sam3n_ek/sam3n_ek.h" +# include "system_sam3n.h" +#elif BOARD == SAM4S_EK +# include "sam4s_ek/sam4s_ek.h" +# include "system_sam4s.h" +#elif BOARD == SAM4S_WPIR_RD +# include "sam4s_wpir_rd/sam4s_wpir_rd.h" +# include "system_sam4s.h" +#elif BOARD == SAM4S_XPLAINED +# include "sam4s_xplained/sam4s_xplained.h" +# include "system_sam4s.h" +#elif BOARD == SAM4S_EK2 +# include "sam4s_ek2/sam4s_ek2.h" +# include "system_sam4s.h" +#elif BOARD == MEGA_1284P_XPLAINED + /*No header-file to include*/ +#elif BOARD == ARDUINO_DUE_X +# include "arduino_due_x/arduino_due_x.h" +# include "system_sam3x.h" +#elif BOARD == SAM4L_EK +# include "sam4l_ek/sam4l_ek.h" +#elif BOARD == SAM4E_EK +# include "sam4e_ek/sam4e_ek.h" +#elif BOARD == SAMD20_XPLAINED_PRO +# include "samd20_xplained_pro/samd20_xplained_pro.h" +#elif BOARD == SAMD21_XPLAINED_PRO +# include "samd21_xplained_pro/samd21_xplained_pro.h" +#elif BOARD == SAMR21_XPLAINED_PRO +# include "samr21_xplained_pro/samr21_xplained_pro.h" +#elif BOARD == SAMR30_XPLAINED_PRO && defined(__SAMR30G18A__) +# include "samr30_xplained_pro/samr30_xplained_pro.h" +#elif BOARD == SAMR30_MODULE_XPLAINED_PRO && defined(__SAMR30E18A__) +# include "samr30_module_xplained_pro/samr30_module_xplained_pro.h" +#elif BOARD == SAMR21ZLL_EK +# include "samr21zll_ek/samr21zll_ek.h" +#elif BOARD == SAMD11_XPLAINED_PRO +# include "samd11_xplained_pro/samd11_xplained_pro.h" +#elif BOARD == SAML21_XPLAINED_PRO && defined(__SAML21J18A__) +# include "saml21_xplained_pro/saml21_xplained_pro.h" +#elif BOARD == SAML22_XPLAINED_PRO +# include "saml22_xplained_pro/saml22_xplained_pro.h" +#elif BOARD == SAML22_XPLAINED_PRO_B +# include "saml22_xplained_pro_b/saml22_xplained_pro_b.h" +#elif BOARD == SAML21_XPLAINED_PRO && defined(__SAML21J18B__) +# include "saml21_xplained_pro_b/saml21_xplained_pro.h" +#elif BOARD == SAMD10_XPLAINED_MINI +# include "samd10_xplained_mini/samd10_xplained_mini.h" +#elif BOARD == SAMDA1_XPLAINED_PRO +# include "samda1_xplained_pro/samda1_xplained_pro.h" +#elif BOARD == SAMHA1G16A_XPLAINED_PRO +# include "samha1g16a_xplained_pro/samha1g16a_xplained_pro.h" +#elif BOARD == SAMC21_XPLAINED_PRO +# include "samc21_xplained_pro/samc21_xplained_pro.h" +#elif BOARD == SAM4N_XPLAINED_PRO +# include "sam4n_xplained_pro/sam4n_xplained_pro.h" +#elif BOARD == SAMW25_XPLAINED_PRO +# include "samw25_xplained_pro/samw25_xplained_pro.h" +#elif BOARD == SAMV71_XPLAINED_ULTRA +# include "samv71_xplained_ultra/samv71_xplained_ultra.h" +#elif BOARD == MEGA1284P_XPLAINED_BC +# include "mega1284p_xplained_bc/mega1284p_xplained_bc.h" +#elif BOARD == UC3_L0_QT600 +# include "uc3_l0_qt600/uc3_l0_qt600.h" +#elif BOARD == XMEGA_A3BU_XPLAINED +# include "xmega_a3bu_xplained/xmega_a3bu_xplained.h" +#elif BOARD == XMEGA_E5_XPLAINED +# include "xmega_e5_xplained/xmega_e5_xplained.h" +#elif BOARD == UC3B_BOARD_CONTROLLER +# include "uc3b_board_controller/uc3b_board_controller.h" +#elif BOARD == RZ600 +# include "rz600/rz600.h" +#elif BOARD == STK600_RCUC3A0 +# include "stk600/rcuc3a0/stk600_rcuc3a0.h" +#elif BOARD == ATXMEGA128A1_QT600 +# include "atxmega128a1_qt600/atxmega128a1_qt600.h" +#elif BOARD == STK600_RCUC3L3 +# include "stk600/rcuc3l3/stk600_rcuc3l3.h" +#elif BOARD == SAM4S_XPLAINED_PRO +# include "sam4s_xplained_pro/sam4s_xplained_pro.h" +#elif BOARD == SAM4L_XPLAINED_PRO +# include "sam4l_xplained_pro/sam4l_xplained_pro.h" +#elif BOARD == SAM4L8_XPLAINED_PRO +# include "sam4l8_xplained_pro/sam4l8_xplained_pro.h" +#elif BOARD == SAM4C_EK +# include "sam4c_ek/sam4c_ek.h" +#elif BOARD == SAM4CMP_DB +# include "sam4cmp_db/sam4cmp_db.h" +#elif BOARD == SAM4CMS_DB +# include "sam4cms_db/sam4cms_db.h" +#elif BOARD == SAM4CP16BMB +# include "sam4cp16bmb/sam4cp16bmb.h" +#elif BOARD == ATPL230AMB +# include "atpl230amb/atpl230amb.h" +#elif BOARD == XMEGA_C3_XPLAINED +# include "xmega_c3_xplained/xmega_c3_xplained.h" +#elif BOARD == XMEGA_RF233_ZIGBIT +# include "xmega_rf233_zigbit/xmega_rf233_zigbit.h" +#elif BOARD == XMEGA_A3_REB_CBB +# include "xmega_a3_reb_cbb/xmega_a3_reb_cbb.h" +#elif BOARD == ATMEGARFX_RCB +# include "atmegarfx_rcb/atmegarfx_rcb.h" +#elif BOARD == RCB256RFR2_XPRO +# include "atmega256rfr2_rcb_xpro/atmega256rfr2_rcb_xpro.h" +#elif BOARD == XMEGA_RF212B_ZIGBIT +# include "xmega_rf212b_zigbit/xmega_rf212b_zigbit.h" +#elif BOARD == SAM4E_XPLAINED_PRO +# include "sam4e_xplained_pro/sam4e_xplained_pro.h" +#elif BOARD == ATMEGA328P_XPLAINED_MINI +# include "atmega328p_xplained_mini/atmega328p_xplained_mini.h" +#elif BOARD == ATMEGA328PB_XPLAINED_MINI +# include "atmega328pb_xplained_mini/atmega328pb_xplained_mini.h" +#elif BOARD == SAMB11_XPLAINED_PRO +# include "samb11_xplained_pro/samb11_xplained_pro.h" +#elif BOARD == SAME70_XPLAINED +# include "same70_xplained/same70_xplained.h" +#elif BOARD == ATMEGA168PB_XPLAINED_MINI +# include "atmega168pb_xplained_mini/atmega168pb_xplained_mini.h" +#elif BOARD == ATMEGA324PB_XPLAINED_PRO +# include "atmega324pb_xplained_pro/atmega324pb_xplained_pro.h" +#elif BOARD == SAMB11ZR_XPLAINED_PRO +# include "samb11zr_xplained_pro/samb11zr_xplained_pro.h" +#elif BOARD == SIMULATOR_XMEGA_A1 +# include "simulator/xmega_a1/simulator_xmega_a1.h" +#elif BOARD == AVR_SIMULATOR_UC3 +# include "avr_simulator_uc3/avr_simulator_uc3.h" +#elif BOARD == SAMR21G18_MODULE +# include "samr21g18_module/samr21g18_module.h" +#elif BOARD == SAMR21B18_MODULE +# include "samr21b18_module/samr21b18_module.h" +#elif BOARD == SAMR34_XPLAINED_PRO && defined(__SAMR34J18B__) +# include "samr34_xplained_pro/samr34_xplained_pro.h" +#elif BOARD == WLR089_XPLAINED_PRO && defined(__WLR089U0__) +# include "wlr089_xplained_pro/wlr089_xplained_pro.h" +#elif BOARD == USER_BOARD +// User-reserved area: #include the header file of your board here (if any). +# include "user_board.h" +#elif BOARD == DUMMY_BOARD +# include "dummy/dummy_board.h" +#elif BOARD == SAMB11ZR_SENSOR_TAG +# include "samb11zr_sensor_tag/samb11zr_sensor_tag.h" +#else +# error No known Atmel board defined +#endif + +#if (defined EXT_BOARD) +# if EXT_BOARD == MC300 +# include "mc300/mc300.h" +# elif (EXT_BOARD == SENSORS_XPLAINED_INERTIAL_1) || \ + (EXT_BOARD == SENSORS_XPLAINED_INERTIAL_2) || \ + (EXT_BOARD == SENSORS_XPLAINED_INERTIAL_A1) || \ + (EXT_BOARD == SENSORS_XPLAINED_PRESSURE_1) || \ + (EXT_BOARD == SENSORS_XPLAINED_LIGHTPROX_1) || \ + (EXT_BOARD == SENSORS_XPLAINED_BREADBOARD) +# include "sensors_xplained/sensors_xplained.h" +# elif EXT_BOARD == RZ600_AT86RF231 +# include "at86rf231/at86rf231.h" +# elif EXT_BOARD == RZ600_AT86RF230B +# include "at86rf230b/at86rf230b.h" +# elif EXT_BOARD == RZ600_AT86RF212 +# include "at86rf212/at86rf212.h" +# elif EXT_BOARD == SECURITY_XPLAINED +# include "security_xplained.h" +# elif EXT_BOARD == USER_EXT_BOARD + // User-reserved area: #include the header file of your extension board here + // (if any). +# endif +#endif + + +#if (defined(__GNUC__) && defined(__AVR32__)) || (defined(__ICCAVR32__) || defined(__AAVR32__)) +#ifdef __AVR32_ABI_COMPILER__ // Automatically defined when compiling for AVR32, not when assembling. + +/*! \brief This function initializes the board target resources + * + * This function should be called to ensure proper initialization of the target + * board hardware connected to the part. + */ +extern void board_init(void); + +#endif // #ifdef __AVR32_ABI_COMPILER__ +#else +/*! \brief This function initializes the board target resources + * + * This function should be called to ensure proper initialization of the target + * board hardware connected to the part. + */ +extern void board_init(void); +#endif + + +#ifdef __cplusplus +} +#endif + +/** + * \} + */ + +#endif // _BOARD_H_ diff --git a/src/boards/mcu/samr34/ASF/common/services/serial/sam0_usart/usart_serial.h b/src/boards/mcu/samr34/ASF/common/services/serial/sam0_usart/usart_serial.h new file mode 100644 index 000000000..c8c9ebb97 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/common/services/serial/sam0_usart/usart_serial.h @@ -0,0 +1,141 @@ +/** + * \file + * + * \brief USART Serial wrapper service for the SAM D/L/C/R devices. + * + * Copyright (c) 2009-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#ifndef _USART_SERIAL_H_ +#define _USART_SERIAL_H_ + +#include "compiler.h" +#include "status_codes.h" +#include "usart.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** \name Serial Management Configuration */ + +typedef Sercom * usart_inst_t; + +//struct usart_module usart; + +/*! \brief Initializes the Usart in serial mode. + * + * \param[in,out] module Software instance of the USART to initialize. + * \param[in] hw Base address of the hardware USART. + * \param[in] config Configuration settings for the USART. + * + * \retval true if the initialization was successful + * \retval false if initialization failed (error in baud rate calculation) + */ +static inline bool usart_serial_init( + struct usart_module *const module, + usart_inst_t const hw, + const struct usart_config *const config) +{ + if (usart_init(module, hw, config) == STATUS_OK) { + return true; + } + else { + return false; + } +} + +/** \brief Sends a character with the USART. + * + * \param[in,out] module Software instance of the USART. + * \param[in] c Character to write. + * + * \return Status code + */ +static inline enum status_code usart_serial_putchar( + struct usart_module *const module, + uint8_t c) +{ + while(STATUS_OK !=usart_write_wait(module, c)); + + return STATUS_OK; +} + +/** \brief Waits until a character is received, and returns it. + * + * \param[in,out] module Software instance of the USART. + * \param[out] c Destination for the read character. + */ +static inline void usart_serial_getchar( + struct usart_module *const module, + uint8_t *c) +{ + uint16_t temp = 0; + + while(STATUS_OK != usart_read_wait(module, &temp)); + + *c = temp; +} + +/** + * \brief Send a sequence of bytes to USART device + * + * \param[in,out] module Software instance of the USART. + * \param[in] tx_data Data buffer to read the data to write from. + * \param[in] length Length of data to write. + */ +static inline enum status_code usart_serial_write_packet( + struct usart_module *const module, + const uint8_t *tx_data, + uint16_t length) +{ + return usart_write_buffer_wait(module, tx_data, length); +} + +/** + * \brief Receive a sequence of bytes from USART device + * + * \param[in,out] module Software instance of the USART. + * \param[out] rx_data Data buffer to store the read data into. + * \param[in] length Length of data to read. + */ +static inline enum status_code usart_serial_read_packet( + struct usart_module *const module, + uint8_t *rx_data, + uint16_t length) +{ + return usart_read_buffer_wait(module, rx_data, length); +} + +#ifdef __cplusplus +} +#endif + +#endif // _USART_SERIAL_H_ diff --git a/src/boards/mcu/samr34/ASF/common/services/serial/serial.h b/src/boards/mcu/samr34/ASF/common/services/serial/serial.h new file mode 100644 index 000000000..425d4ebdb --- /dev/null +++ b/src/boards/mcu/samr34/ASF/common/services/serial/serial.h @@ -0,0 +1,269 @@ +/** + * \file + * + * \brief Serial Mode management + * + * Copyright (c) 2010-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#ifndef SERIAL_H_INCLUDED +#define SERIAL_H_INCLUDED + +#include +#include "status_codes.h" + +/** + * \typedef usart_if + * + * This type can be used independently to refer to USART module for the + * architecture used. It refers to the correct type definition for the + * architecture, ie. USART_t* for XMEGA or avr32_usart_t* for UC3. + */ + +#if XMEGA +# include "xmega_usart/usart_serial.h" +#elif MEGA_RF +# include "megarf_usart/usart_serial.h" +#elif UC3 +# include "uc3_usart/usart_serial.h" +#elif (SAMB) +#include "samb_uart/uart_serial.h" +#elif (SAM0) +#include "sam0_usart/usart_serial.h" +#elif SAM +# include "sam_uart/uart_serial.h" +#else +# error Unsupported chip type +#endif + +/** + * + * \defgroup serial_group Serial Interface (Serial) + * + * See \ref serial_quickstart. + * + * This is the common API for serial interface. Additional features are available + * in the documentation of the specific modules. + * + * \section serial_group_platform Platform Dependencies + * + * The serial API is partially chip- or platform-specific. While all + * platforms provide mostly the same functionality, there are some + * variations around how different bus types and clock tree structures + * are handled. + * + * The following functions are available on all platforms, but there may + * be variations in the function signature (i.e. parameters) and + * behaviour. These functions are typically called by platform-specific + * parts of drivers, and applications that aren't intended to be + * portable: + * - usart_serial_init() + * - usart_serial_putchar() + * - usart_serial_getchar() + * - usart_serial_write_packet() + * - usart_serial_read_packet() + * + * + * @{ + */ + +//! @} + +/** + * \page serial_quickstart Quick start guide for Serial Interface service + * + * This is the quick start guide for the \ref serial_group "Serial Interface module", with + * step-by-step instructions on how to configure and use the serial in a + * selection of use cases. + * + * The use cases contain several code fragments. The code fragments in the + * steps for setup can be copied into a custom initialization function, while + * the steps for usage can be copied into, e.g., the main application function. + * + * \section serial_use_cases Serial use cases + * - \ref serial_basic_use_case + * - \subpage serial_use_case_1 + * + * \section serial_basic_use_case Basic use case - transmit a character + * In this use case, the serial module is configured for: + * - Using USARTD0 + * - Baudrate: 9600 + * - Character length: 8 bit + * - Parity mode: Disabled + * - Stop bit: None + * - RS232 mode + * + * The use case waits for a received character on the configured USART and + * echoes the character back to the same USART. + * + * \section serial_basic_use_case_setup Setup steps + * + * \subsection serial_basic_use_case_setup_prereq Prerequisites + * -# \ref sysclk_group "System Clock Management (sysclk)" + * + * \subsection serial_basic_use_case_setup_code Example code + * The following configuration must be added to the project (typically to a + * conf_uart_serial.h file, but it can also be added to your main application file.) + * + * \note The following takes SAM3X configuration for example, other devices have similar + * configuration, but their parameters may be different, refer to corresponding header files. + * + * \code + #define USART_SERIAL &USARTD0 + #define USART_SERIAL_BAUDRATE 9600 + #define USART_SERIAL_CHAR_LENGTH US_MR_CHRL_8_BIT + #define USART_SERIAL_PARITY US_MR_PAR_NO + #define USART_SERIAL_STOP_BIT false +\endcode + * + * A variable for the received byte must be added: + * \code uint8_t received_byte; \endcode + * + * Add to application initialization: + * \code + sysclk_init(); + + static usart_serial_options_t usart_options = { + .baudrate = USART_SERIAL_BAUDRATE, + .charlength = USART_SERIAL_CHAR_LENGTH, + .paritytype = USART_SERIAL_PARITY, + .stopbits = USART_SERIAL_STOP_BIT + }; + + usart_serial_init(USART_SERIAL, &usart_options); +\endcode + * + * \subsection serial_basic_use_case_setup_flow Workflow + * -# Initialize system clock: + * - \code sysclk_init(); \endcode + * -# Create serial USART options struct: + * - \code + static usart_serial_options_t usart_options = { + .baudrate = USART_SERIAL_BAUDRATE, + .charlength = USART_SERIAL_CHAR_LENGTH, + .paritytype = USART_SERIAL_PARITY, + .stopbits = USART_SERIAL_STOP_BIT + }; +\endcode + * -# Initialize the serial service: + * - \code usart_serial_init(USART_SERIAL, &usart_options);\endcode + * + * \section serial_basic_use_case_usage Usage steps + * + * \subsection serial_basic_use_case_usage_code Example code + * Add to application C-file: + * \code + usart_serial_getchar(USART_SERIAL, &received_byte); + usart_serial_putchar(USART_SERIAL, received_byte); +\endcode + * + * \subsection serial_basic_use_case_usage_flow Workflow + * -# Wait for reception of a character: + * - \code usart_serial_getchar(USART_SERIAL, &received_byte); \endcode + * -# Echo the character back: + * - \code usart_serial_putchar(USART_SERIAL, received_byte); \endcode + */ + +/** + * \page serial_use_case_1 Advanced use case - Send a packet of serial data + * + * In this use case, the USART module is configured for: + * - Using USARTD0 + * - Baudrate: 9600 + * - Character length: 8 bit + * - Parity mode: Disabled + * - Stop bit: None + * - RS232 mode + * + * The use case sends a string of text through the USART. + * + * \section serial_use_case_1_setup Setup steps + * + * \subsection serial_use_case_1_setup_prereq Prerequisites + * -# \ref sysclk_group "System Clock Management (sysclk)" + * + * \subsection serial_use_case_1_setup_code Example code + * The following configuration must be added to the project (typically to a + * conf_uart_serial.h file, but it can also be added to your main application file.): + * + * \note The following takes SAM3X configuration for example, other devices have similar + * configuration, but their parameters may be different, refer to corresponding header files. + * + * \code + #define USART_SERIAL &USARTD0 + #define USART_SERIAL_BAUDRATE 9600 + #define USART_SERIAL_CHAR_LENGTH US_MR_CHRL_8_BIT + #define USART_SERIAL_PARITY US_MR_PAR_NO + #define USART_SERIAL_STOP_BIT false +\endcode + * + * Add to application initialization: + * \code + sysclk_init(); + + static usart_serial_options_t usart_options = { + .baudrate = USART_SERIAL_BAUDRATE, + .charlength = USART_SERIAL_CHAR_LENGTH, + .paritytype = USART_SERIAL_PARITY, + .stopbits = USART_SERIAL_STOP_BIT + }; + + usart_serial_init(USART_SERIAL, &usart_options); +\endcode + * + * \subsection serial_use_case_1_setup_flow Workflow + * -# Initialize system clock: + * - \code sysclk_init(); \endcode + * -# Create USART options struct: + * - \code + static usart_serial_options_t usart_options = { + .baudrate = USART_SERIAL_BAUDRATE, + .charlength = USART_SERIAL_CHAR_LENGTH, + .paritytype = USART_SERIAL_PARITY, + .stopbits = USART_SERIAL_STOP_BIT + }; +\endcode + * -# Initialize in RS232 mode: + * - \code usart_serial_init(USART_SERIAL_EXAMPLE, &usart_options); \endcode + * + * \section serial_use_case_1_usage Usage steps + * + * \subsection serial_use_case_1_usage_code Example code + * Add to, e.g., main loop in application C-file: + * \code + usart_serial_write_packet(USART_SERIAL, "Test String", strlen("Test String")); +\endcode + * + * \subsection serial_use_case_1_usage_flow Workflow + * -# Write a string of text to the USART: + * - \code usart_serial_write_packet(USART_SERIAL, "Test String", strlen("Test String")); \endcode + */ + +#endif /* SERIAL_H_INCLUDED */ diff --git a/src/boards/mcu/samr34/ASF/common/utils/interrupt.h b/src/boards/mcu/samr34/ASF/common/utils/interrupt.h new file mode 100644 index 000000000..e5154a6ff --- /dev/null +++ b/src/boards/mcu/samr34/ASF/common/utils/interrupt.h @@ -0,0 +1,132 @@ +/** + * \file + * + * \brief Global interrupt management for 8- and 32-bit AVR + * + * Copyright (c) 2010-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#ifndef UTILS_INTERRUPT_H +#define UTILS_INTERRUPT_H + +#include + +#if XMEGA || MEGA +# include "interrupt/interrupt_avr8.h" +#elif UC3 +# include "interrupt/interrupt_avr32.h" +#elif SAM || SAMB +# include "interrupt/interrupt_sam_nvic.h" +#else +# error Unsupported device. +#endif + +/** + * \defgroup interrupt_group Global interrupt management + * + * This is a driver for global enabling and disabling of interrupts. + * + * @{ + */ + +#if defined(__DOXYGEN__) +/** + * \def CONFIG_INTERRUPT_FORCE_INTC + * \brief Force usage of the ASF INTC driver + * + * Predefine this symbol when preprocessing to force the use of the ASF INTC driver. + * This is useful to ensure compatibility across compilers and shall be used only when required + * by the application needs. + */ +# define CONFIG_INTERRUPT_FORCE_INTC +#endif + +//! \name Global interrupt flags +//@{ +/** + * \typedef irqflags_t + * \brief Type used for holding state of interrupt flag + */ + +/** + * \def cpu_irq_enable + * \brief Enable interrupts globally + */ + +/** + * \def cpu_irq_disable + * \brief Disable interrupts globally + */ + +/** + * \fn irqflags_t cpu_irq_save(void) + * \brief Get and clear the global interrupt flags + * + * Use in conjunction with \ref cpu_irq_restore. + * + * \return Current state of interrupt flags. + * + * \note This function leaves interrupts disabled. + */ + +/** + * \fn void cpu_irq_restore(irqflags_t flags) + * \brief Restore global interrupt flags + * + * Use in conjunction with \ref cpu_irq_save. + * + * \param flags State to set interrupt flag to. + */ + +/** + * \fn bool cpu_irq_is_enabled_flags(irqflags_t flags) + * \brief Check if interrupts are globally enabled in supplied flags + * + * \param flags Currents state of interrupt flags. + * + * \return True if interrupts are enabled. + */ + +/** + * \def cpu_irq_is_enabled + * \brief Check if interrupts are globally enabled + * + * \return True if interrupts are enabled. + */ +//@} + +//! @} + +/** + * \ingroup interrupt_group + * \defgroup interrupt_deprecated_group Deprecated interrupt definitions + */ + +#endif /* UTILS_INTERRUPT_H */ diff --git a/src/boards/mcu/samr34/ASF/common/utils/interrupt/interrupt_sam_nvic.c b/src/boards/mcu/samr34/ASF/common/utils/interrupt/interrupt_sam_nvic.c new file mode 100644 index 000000000..534f54147 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/common/utils/interrupt/interrupt_sam_nvic.c @@ -0,0 +1,76 @@ +/** + * \file + * + * \brief Global interrupt management for SAM D20, SAM3 and SAM4 (NVIC based) + * + * Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#include "interrupt_sam_nvic.h" + +#if !defined(__DOXYGEN__) +/* Deprecated - global flag to determine the global interrupt state. Required by + * QTouch library, however new applications should use cpu_irq_is_enabled() + * which probes the true global interrupt state from the CPU special registers. + */ +volatile bool g_interrupt_enabled = true; +#endif + +void cpu_irq_enter_critical(void) +{ + if (cpu_irq_critical_section_counter == 0) { + if (cpu_irq_is_enabled()) { + cpu_irq_disable(); + cpu_irq_prev_interrupt_state = true; + } else { + /* Make sure the to save the prev state as false */ + cpu_irq_prev_interrupt_state = false; + } + + } + + cpu_irq_critical_section_counter++; +} + +void cpu_irq_leave_critical(void) +{ + /* Check if the user is trying to leave a critical section when not in a critical section */ + Assert(cpu_irq_critical_section_counter > 0); + + cpu_irq_critical_section_counter--; + + /* Only enable global interrupts when the counter reaches 0 and the state of the global interrupt flag + was enabled when entering critical state */ + if ((cpu_irq_critical_section_counter == 0) && (cpu_irq_prev_interrupt_state)) { + cpu_irq_enable(); + } +} + diff --git a/src/boards/mcu/samr34/ASF/common/utils/interrupt/interrupt_sam_nvic.h b/src/boards/mcu/samr34/ASF/common/utils/interrupt/interrupt_sam_nvic.h new file mode 100644 index 000000000..d7b3193d3 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/common/utils/interrupt/interrupt_sam_nvic.h @@ -0,0 +1,179 @@ +/** + * \file + * + * \brief Global interrupt management for SAM D20, SAM3 and SAM4 (NVIC based) + * + * Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#ifndef UTILS_INTERRUPT_INTERRUPT_H +#define UTILS_INTERRUPT_INTERRUPT_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \weakgroup interrupt_group + * + * @{ + */ + +/** + * \name Interrupt Service Routine definition + * + * @{ + */ + +/** + * \brief Define service routine + * + * \note For NVIC devices the interrupt service routines are predefined to + * add to vector table in binary generation, so there is no service + * register at run time. The routine collections are in exceptions.h. + * + * Usage: + * \code + ISR(foo_irq_handler) + { + // Function definition + ... + } +\endcode + * + * \param func Name for the function. + */ +# define ISR(func) \ + void func (void) + +/** + * \brief Initialize interrupt vectors + * + * For NVIC the interrupt vectors are put in vector table. So nothing + * to do to initialize them, except defined the vector function with + * right name. + * + * This must be called prior to \ref irq_register_handler. + */ +# define irq_initialize_vectors() \ + do { \ + } while(0) + +/** + * \brief Register handler for interrupt + * + * For NVIC the interrupt vectors are put in vector table. So nothing + * to do to register them, except defined the vector function with + * right name. + * + * Usage: + * \code + irq_initialize_vectors(); + irq_register_handler(foo_irq_handler); +\endcode + * + * \note The function \a func must be defined with the \ref ISR macro. + * \note The functions prototypes can be found in the device exception header + * files (exceptions.h). + */ +# define irq_register_handler(int_num, int_prio) \ + NVIC_ClearPendingIRQ( (IRQn_Type)int_num); \ + NVIC_SetPriority( (IRQn_Type)int_num, int_prio); \ + NVIC_EnableIRQ( (IRQn_Type)int_num); \ + +//@} + +# define cpu_irq_enable() \ + do { \ + g_interrupt_enabled = true; \ + __DMB(); \ + __enable_irq(); \ + } while (0) +# define cpu_irq_disable() \ + do { \ + __disable_irq(); \ + __DMB(); \ + g_interrupt_enabled = false; \ + } while (0) + +typedef uint32_t irqflags_t; + +#if !defined(__DOXYGEN__) +extern volatile bool g_interrupt_enabled; +#endif + +#define cpu_irq_is_enabled() (__get_PRIMASK() == 0) + +static volatile uint32_t cpu_irq_critical_section_counter; +static volatile bool cpu_irq_prev_interrupt_state; + +static inline irqflags_t cpu_irq_save(void) +{ + volatile irqflags_t flags = cpu_irq_is_enabled(); + cpu_irq_disable(); + return flags; +} + +static inline bool cpu_irq_is_enabled_flags(irqflags_t flags) +{ + return (flags); +} + +static inline void cpu_irq_restore(irqflags_t flags) +{ + if (cpu_irq_is_enabled_flags(flags)) + cpu_irq_enable(); +} + +void cpu_irq_enter_critical(void); +void cpu_irq_leave_critical(void); + +/** + * \weakgroup interrupt_deprecated_group + * @{ + */ + +#define Enable_global_interrupt() cpu_irq_enable() +#define Disable_global_interrupt() cpu_irq_disable() +#define Is_global_interrupt_enabled() cpu_irq_is_enabled() + +//@} + +//@} + +#ifdef __cplusplus +} +#endif + +#endif /* UTILS_INTERRUPT_INTERRUPT_H */ diff --git a/src/boards/mcu/samr34/ASF/common/utils/parts.h b/src/boards/mcu/samr34/ASF/common/utils/parts.h new file mode 100644 index 000000000..0dcd42629 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/common/utils/parts.h @@ -0,0 +1,1768 @@ +/** + * \file + * + * \brief Atmel part identification macros + * + * Copyright (c) 2012-2020 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#ifndef ATMEL_PARTS_H +#define ATMEL_PARTS_H + +/** + * \defgroup part_macros_group Atmel part identification macros + * + * This collection of macros identify which series and families that the various + * Atmel parts belong to. These can be used to select part-dependent sections of + * code at compile time. + * + * @{ + */ + +/** + * \name Convenience macros for part checking + * @{ + */ +/* ! Check GCC and IAR part definition for 8-bit AVR */ +#define AVR8_PART_IS_DEFINED(part) \ + (defined(__ ## part ## __) || defined(__AVR_ ## part ## __)) + +/* ! Check GCC and IAR part definition for 32-bit AVR */ +#define AVR32_PART_IS_DEFINED(part) \ + (defined(__AT32 ## part ## __) || defined(__AVR32_ ## part ## __)) + +/* ! Check GCC and IAR part definition for SAM */ +#define SAM_PART_IS_DEFINED(part) (defined(__ ## part ## __)) +/** @} */ + +/** + * \defgroup uc3_part_macros_group AVR UC3 parts + * @{ + */ + +/** + * \name AVR UC3 A series + * @{ + */ +#define UC3A0 ( \ + AVR32_PART_IS_DEFINED(UC3A0128) || \ + AVR32_PART_IS_DEFINED(UC3A0256) || \ + AVR32_PART_IS_DEFINED(UC3A0512) \ + ) + +#define UC3A1 ( \ + AVR32_PART_IS_DEFINED(UC3A1128) || \ + AVR32_PART_IS_DEFINED(UC3A1256) || \ + AVR32_PART_IS_DEFINED(UC3A1512) \ + ) + +#define UC3A3 ( \ + AVR32_PART_IS_DEFINED(UC3A364) || \ + AVR32_PART_IS_DEFINED(UC3A364S) || \ + AVR32_PART_IS_DEFINED(UC3A3128) || \ + AVR32_PART_IS_DEFINED(UC3A3128S) || \ + AVR32_PART_IS_DEFINED(UC3A3256) || \ + AVR32_PART_IS_DEFINED(UC3A3256S) \ + ) + +#define UC3A4 ( \ + AVR32_PART_IS_DEFINED(UC3A464) || \ + AVR32_PART_IS_DEFINED(UC3A464S) || \ + AVR32_PART_IS_DEFINED(UC3A4128) || \ + AVR32_PART_IS_DEFINED(UC3A4128S) || \ + AVR32_PART_IS_DEFINED(UC3A4256) || \ + AVR32_PART_IS_DEFINED(UC3A4256S) \ + ) +/** @} */ + +/** + * \name AVR UC3 B series + * @{ + */ +#define UC3B0 ( \ + AVR32_PART_IS_DEFINED(UC3B064) || \ + AVR32_PART_IS_DEFINED(UC3B0128) || \ + AVR32_PART_IS_DEFINED(UC3B0256) || \ + AVR32_PART_IS_DEFINED(UC3B0512) \ + ) + +#define UC3B1 ( \ + AVR32_PART_IS_DEFINED(UC3B164) || \ + AVR32_PART_IS_DEFINED(UC3B1128) || \ + AVR32_PART_IS_DEFINED(UC3B1256) || \ + AVR32_PART_IS_DEFINED(UC3B1512) \ + ) +/** @} */ + +/** + * \name AVR UC3 C series + * @{ + */ +#define UC3C0 ( \ + AVR32_PART_IS_DEFINED(UC3C064C) || \ + AVR32_PART_IS_DEFINED(UC3C0128C) || \ + AVR32_PART_IS_DEFINED(UC3C0256C) || \ + AVR32_PART_IS_DEFINED(UC3C0512C) \ + ) + +#define UC3C1 ( \ + AVR32_PART_IS_DEFINED(UC3C164C) || \ + AVR32_PART_IS_DEFINED(UC3C1128C) || \ + AVR32_PART_IS_DEFINED(UC3C1256C) || \ + AVR32_PART_IS_DEFINED(UC3C1512C) \ + ) + +#define UC3C2 ( \ + AVR32_PART_IS_DEFINED(UC3C264C) || \ + AVR32_PART_IS_DEFINED(UC3C2128C) || \ + AVR32_PART_IS_DEFINED(UC3C2256C) || \ + AVR32_PART_IS_DEFINED(UC3C2512C) \ + ) +/** @} */ + +/** + * \name AVR UC3 D series + * @{ + */ +#define UC3D3 ( \ + AVR32_PART_IS_DEFINED(UC64D3) || \ + AVR32_PART_IS_DEFINED(UC128D3) \ + ) + +#define UC3D4 ( \ + AVR32_PART_IS_DEFINED(UC64D4) || \ + AVR32_PART_IS_DEFINED(UC128D4) \ + ) +/** @} */ + +/** + * \name AVR UC3 L series + * @{ + */ +#define UC3L0 ( \ + AVR32_PART_IS_DEFINED(UC3L016) || \ + AVR32_PART_IS_DEFINED(UC3L032) || \ + AVR32_PART_IS_DEFINED(UC3L064) \ + ) + +#define UC3L0128 ( \ + AVR32_PART_IS_DEFINED(UC3L0128) \ + ) + +#define UC3L0256 ( \ + AVR32_PART_IS_DEFINED(UC3L0256) \ + ) + +#define UC3L3 ( \ + AVR32_PART_IS_DEFINED(UC64L3U) || \ + AVR32_PART_IS_DEFINED(UC128L3U) || \ + AVR32_PART_IS_DEFINED(UC256L3U) \ + ) + +#define UC3L4 ( \ + AVR32_PART_IS_DEFINED(UC64L4U) || \ + AVR32_PART_IS_DEFINED(UC128L4U) || \ + AVR32_PART_IS_DEFINED(UC256L4U) \ + ) + +#define UC3L3_L4 (UC3L3 || UC3L4) +/** @} */ + +/** + * \name AVR UC3 families + * @{ + */ +/** AVR UC3 A family */ +#define UC3A (UC3A0 || UC3A1 || UC3A3 || UC3A4) + +/** AVR UC3 B family */ +#define UC3B (UC3B0 || UC3B1) + +/** AVR UC3 C family */ +#define UC3C (UC3C0 || UC3C1 || UC3C2) + +/** AVR UC3 D family */ +#define UC3D (UC3D3 || UC3D4) + +/** AVR UC3 L family */ +#define UC3L (UC3L0 || UC3L0128 || UC3L0256 || UC3L3_L4) +/** @} */ + +/** AVR UC3 product line */ +#define UC3 (UC3A || UC3B || UC3C || UC3D || UC3L) + +/** @} */ + +/** + * \defgroup xmega_part_macros_group AVR XMEGA parts + * @{ + */ + +/** + * \name AVR XMEGA A series + * @{ + */ +#define XMEGA_A1 ( \ + AVR8_PART_IS_DEFINED(ATxmega64A1) || \ + AVR8_PART_IS_DEFINED(ATxmega128A1) \ + ) + +#define XMEGA_A3 ( \ + AVR8_PART_IS_DEFINED(ATxmega64A3) || \ + AVR8_PART_IS_DEFINED(ATxmega128A3) || \ + AVR8_PART_IS_DEFINED(ATxmega192A3) || \ + AVR8_PART_IS_DEFINED(ATxmega256A3) \ + ) + +#define XMEGA_A3B ( \ + AVR8_PART_IS_DEFINED(ATxmega256A3B) \ + ) + +#define XMEGA_A4 ( \ + AVR8_PART_IS_DEFINED(ATxmega16A4) || \ + AVR8_PART_IS_DEFINED(ATxmega32A4) \ + ) +/** @} */ + +/** + * \name AVR XMEGA AU series + * @{ + */ +#define XMEGA_A1U ( \ + AVR8_PART_IS_DEFINED(ATxmega64A1U) || \ + AVR8_PART_IS_DEFINED(ATxmega128A1U) \ + ) + +#define XMEGA_A3U ( \ + AVR8_PART_IS_DEFINED(ATxmega64A3U) || \ + AVR8_PART_IS_DEFINED(ATxmega128A3U) || \ + AVR8_PART_IS_DEFINED(ATxmega192A3U) || \ + AVR8_PART_IS_DEFINED(ATxmega256A3U) \ + ) + +#define XMEGA_A3BU ( \ + AVR8_PART_IS_DEFINED(ATxmega256A3BU) \ + ) + +#define XMEGA_A4U ( \ + AVR8_PART_IS_DEFINED(ATxmega16A4U) || \ + AVR8_PART_IS_DEFINED(ATxmega32A4U) || \ + AVR8_PART_IS_DEFINED(ATxmega64A4U) || \ + AVR8_PART_IS_DEFINED(ATxmega128A4U) \ + ) +/** @} */ + +/** + * \name AVR XMEGA B series + * @{ + */ +#define XMEGA_B1 ( \ + AVR8_PART_IS_DEFINED(ATxmega64B1) || \ + AVR8_PART_IS_DEFINED(ATxmega128B1) \ + ) + +#define XMEGA_B3 ( \ + AVR8_PART_IS_DEFINED(ATxmega64B3) || \ + AVR8_PART_IS_DEFINED(ATxmega128B3) \ + ) +/** @} */ + +/** + * \name AVR XMEGA C series + * @{ + */ +#define XMEGA_C3 ( \ + AVR8_PART_IS_DEFINED(ATxmega384C3) || \ + AVR8_PART_IS_DEFINED(ATxmega256C3) || \ + AVR8_PART_IS_DEFINED(ATxmega192C3) || \ + AVR8_PART_IS_DEFINED(ATxmega128C3) || \ + AVR8_PART_IS_DEFINED(ATxmega64C3) || \ + AVR8_PART_IS_DEFINED(ATxmega32C3) \ + ) + +#define XMEGA_C4 ( \ + AVR8_PART_IS_DEFINED(ATxmega32C4) || \ + AVR8_PART_IS_DEFINED(ATxmega16C4) \ + ) +/** @} */ + +/** + * \name AVR XMEGA D series + * @{ + */ +#define XMEGA_D3 ( \ + AVR8_PART_IS_DEFINED(ATxmega32D3) || \ + AVR8_PART_IS_DEFINED(ATxmega64D3) || \ + AVR8_PART_IS_DEFINED(ATxmega128D3) || \ + AVR8_PART_IS_DEFINED(ATxmega192D3) || \ + AVR8_PART_IS_DEFINED(ATxmega256D3) || \ + AVR8_PART_IS_DEFINED(ATxmega384D3) \ + ) + +#define XMEGA_D4 ( \ + AVR8_PART_IS_DEFINED(ATxmega16D4) || \ + AVR8_PART_IS_DEFINED(ATxmega32D4) || \ + AVR8_PART_IS_DEFINED(ATxmega64D4) || \ + AVR8_PART_IS_DEFINED(ATxmega128D4) \ + ) +/** @} */ + +/** + * \name AVR XMEGA E series + * @{ + */ +#define XMEGA_E5 ( \ + AVR8_PART_IS_DEFINED(ATxmega8E5) || \ + AVR8_PART_IS_DEFINED(ATxmega16E5) || \ + AVR8_PART_IS_DEFINED(ATxmega32E5) \ + ) +/** @} */ + + +/** + * \name AVR XMEGA families + * @{ + */ +/** AVR XMEGA A family */ +#define XMEGA_A (XMEGA_A1 || XMEGA_A3 || XMEGA_A3B || XMEGA_A4) + +/** AVR XMEGA AU family */ +#define XMEGA_AU (XMEGA_A1U || XMEGA_A3U || XMEGA_A3BU || XMEGA_A4U) + +/** AVR XMEGA B family */ +#define XMEGA_B (XMEGA_B1 || XMEGA_B3) + +/** AVR XMEGA C family */ +#define XMEGA_C (XMEGA_C3 || XMEGA_C4) + +/** AVR XMEGA D family */ +#define XMEGA_D (XMEGA_D3 || XMEGA_D4) + +/** AVR XMEGA E family */ +#define XMEGA_E (XMEGA_E5) +/** @} */ + + +/** AVR XMEGA product line */ +#define XMEGA (XMEGA_A || XMEGA_AU || XMEGA_B || XMEGA_C || XMEGA_D || XMEGA_E) + +/** @} */ + +/** + * \defgroup mega_part_macros_group megaAVR parts + * + * \note These megaAVR groupings are based on the groups in AVR Libc for the + * part header files. They are not names of official megaAVR device series or + * families. + * + * @{ + */ + +/** + * \name ATmegaxx0/xx1 subgroups + * @{ + */ +#define MEGA_XX0 ( \ + AVR8_PART_IS_DEFINED(ATmega640) || \ + AVR8_PART_IS_DEFINED(ATmega1280) || \ + AVR8_PART_IS_DEFINED(ATmega2560) \ + ) + +#define MEGA_XX1 ( \ + AVR8_PART_IS_DEFINED(ATmega1281) || \ + AVR8_PART_IS_DEFINED(ATmega2561) \ + ) +/** @} */ + +/** + * \name megaAVR groups + * @{ + */ +/** ATmegaxx0/xx1 group */ +#define MEGA_XX0_1 (MEGA_XX0 || MEGA_XX1) + +/** ATmegaxx4 group */ +#define MEGA_XX4 ( \ + AVR8_PART_IS_DEFINED(ATmega164A) || \ + AVR8_PART_IS_DEFINED(ATmega164PA) || \ + AVR8_PART_IS_DEFINED(ATmega324A) || \ + AVR8_PART_IS_DEFINED(ATmega324PA) || \ + AVR8_PART_IS_DEFINED(ATmega324PB) || \ + AVR8_PART_IS_DEFINED(ATmega644) || \ + AVR8_PART_IS_DEFINED(ATmega644A) || \ + AVR8_PART_IS_DEFINED(ATmega644PA) || \ + AVR8_PART_IS_DEFINED(ATmega1284P) || \ + AVR8_PART_IS_DEFINED(ATmega128RFA1) \ + ) + +/** ATmegaxx4 group */ +#define MEGA_XX4_A ( \ + AVR8_PART_IS_DEFINED(ATmega164A) || \ + AVR8_PART_IS_DEFINED(ATmega164PA) || \ + AVR8_PART_IS_DEFINED(ATmega324A) || \ + AVR8_PART_IS_DEFINED(ATmega324PA) || \ + AVR8_PART_IS_DEFINED(ATmega644A) || \ + AVR8_PART_IS_DEFINED(ATmega644PA) || \ + AVR8_PART_IS_DEFINED(ATmega1284P) \ + ) + +/** ATmegaxx8 group */ +#define MEGA_XX8 ( \ + AVR8_PART_IS_DEFINED(ATmega48) || \ + AVR8_PART_IS_DEFINED(ATmega48A) || \ + AVR8_PART_IS_DEFINED(ATmega48PA) || \ + AVR8_PART_IS_DEFINED(ATmega48PB) || \ + AVR8_PART_IS_DEFINED(ATmega88) || \ + AVR8_PART_IS_DEFINED(ATmega88A) || \ + AVR8_PART_IS_DEFINED(ATmega88PA) || \ + AVR8_PART_IS_DEFINED(ATmega88PB) || \ + AVR8_PART_IS_DEFINED(ATmega168) || \ + AVR8_PART_IS_DEFINED(ATmega168A) || \ + AVR8_PART_IS_DEFINED(ATmega168PA) || \ + AVR8_PART_IS_DEFINED(ATmega168PB) || \ + AVR8_PART_IS_DEFINED(ATmega328) || \ + AVR8_PART_IS_DEFINED(ATmega328P) || \ + AVR8_PART_IS_DEFINED(ATmega328PB) \ + ) + +/** ATmegaxx8A/P/PA group */ +#define MEGA_XX8_A ( \ + AVR8_PART_IS_DEFINED(ATmega48A) || \ + AVR8_PART_IS_DEFINED(ATmega48PA) || \ + AVR8_PART_IS_DEFINED(ATmega88A) || \ + AVR8_PART_IS_DEFINED(ATmega88PA) || \ + AVR8_PART_IS_DEFINED(ATmega168A) || \ + AVR8_PART_IS_DEFINED(ATmega168PA) || \ + AVR8_PART_IS_DEFINED(ATmega328P) \ + ) + +/** ATmegaxx group */ +#define MEGA_XX ( \ + AVR8_PART_IS_DEFINED(ATmega16) || \ + AVR8_PART_IS_DEFINED(ATmega16A) || \ + AVR8_PART_IS_DEFINED(ATmega32) || \ + AVR8_PART_IS_DEFINED(ATmega32A) || \ + AVR8_PART_IS_DEFINED(ATmega64) || \ + AVR8_PART_IS_DEFINED(ATmega64A) || \ + AVR8_PART_IS_DEFINED(ATmega128) || \ + AVR8_PART_IS_DEFINED(ATmega128A) \ + ) + +/** ATmegaxxA/P/PA group */ +#define MEGA_XX_A ( \ + AVR8_PART_IS_DEFINED(ATmega16A) || \ + AVR8_PART_IS_DEFINED(ATmega32A) || \ + AVR8_PART_IS_DEFINED(ATmega64A) || \ + AVR8_PART_IS_DEFINED(ATmega128A) \ + ) +/** ATmegaxxRFA1 group */ +#define MEGA_RFA1 ( \ + AVR8_PART_IS_DEFINED(ATmega128RFA1) \ + ) + +/** ATmegaxxRFR2 group */ +#define MEGA_RFR2 ( \ + AVR8_PART_IS_DEFINED(ATmega64RFR2) || \ + AVR8_PART_IS_DEFINED(ATmega128RFR2) || \ + AVR8_PART_IS_DEFINED(ATmega256RFR2) || \ + AVR8_PART_IS_DEFINED(ATmega644RFR2) || \ + AVR8_PART_IS_DEFINED(ATmega1284RFR2) || \ + AVR8_PART_IS_DEFINED(ATmega2564RFR2) \ + ) + + +/** ATmegaxxRFxx group */ +#define MEGA_RF (MEGA_RFA1 || MEGA_RFR2) + +/** + * \name ATmegaxx_un0/un1/un2 subgroups + * @{ + */ +#define MEGA_XX_UN0 ( \ + AVR8_PART_IS_DEFINED(ATmega16) || \ + AVR8_PART_IS_DEFINED(ATmega16A) || \ + AVR8_PART_IS_DEFINED(ATmega32) || \ + AVR8_PART_IS_DEFINED(ATmega32A) \ + ) + +/** ATmegaxx group without power reduction and + * And interrupt sense register. + */ +#define MEGA_XX_UN1 ( \ + AVR8_PART_IS_DEFINED(ATmega64) || \ + AVR8_PART_IS_DEFINED(ATmega64A) || \ + AVR8_PART_IS_DEFINED(ATmega128) || \ + AVR8_PART_IS_DEFINED(ATmega128A) \ + ) + +/** ATmegaxx group without power reduction and + * And interrupt sense register. + */ +#define MEGA_XX_UN2 ( \ + AVR8_PART_IS_DEFINED(ATmega169P) || \ + AVR8_PART_IS_DEFINED(ATmega169PA) || \ + AVR8_PART_IS_DEFINED(ATmega329P) || \ + AVR8_PART_IS_DEFINED(ATmega329PA) \ + ) + +/** Devices added to complete megaAVR offering. + * Please do not use this group symbol as it is not intended + * to be permanent: the devices should be regrouped. + */ +#define MEGA_UNCATEGORIZED ( \ + AVR8_PART_IS_DEFINED(AT90CAN128) || \ + AVR8_PART_IS_DEFINED(AT90CAN32) || \ + AVR8_PART_IS_DEFINED(AT90CAN64) || \ + AVR8_PART_IS_DEFINED(AT90PWM1) || \ + AVR8_PART_IS_DEFINED(AT90PWM216) || \ + AVR8_PART_IS_DEFINED(AT90PWM2B) || \ + AVR8_PART_IS_DEFINED(AT90PWM316) || \ + AVR8_PART_IS_DEFINED(AT90PWM3B) || \ + AVR8_PART_IS_DEFINED(AT90PWM81) || \ + AVR8_PART_IS_DEFINED(AT90USB1286) || \ + AVR8_PART_IS_DEFINED(AT90USB1287) || \ + AVR8_PART_IS_DEFINED(AT90USB162) || \ + AVR8_PART_IS_DEFINED(AT90USB646) || \ + AVR8_PART_IS_DEFINED(AT90USB647) || \ + AVR8_PART_IS_DEFINED(AT90USB82) || \ + AVR8_PART_IS_DEFINED(ATmega1284) || \ + AVR8_PART_IS_DEFINED(ATmega162) || \ + AVR8_PART_IS_DEFINED(ATmega164P) || \ + AVR8_PART_IS_DEFINED(ATmega165A) || \ + AVR8_PART_IS_DEFINED(ATmega165P) || \ + AVR8_PART_IS_DEFINED(ATmega165PA) || \ + AVR8_PART_IS_DEFINED(ATmega168P) || \ + AVR8_PART_IS_DEFINED(ATmega169A) || \ + AVR8_PART_IS_DEFINED(ATmega16M1) || \ + AVR8_PART_IS_DEFINED(ATmega16U2) || \ + AVR8_PART_IS_DEFINED(ATmega16U4) || \ + AVR8_PART_IS_DEFINED(ATmega256RFA2) || \ + AVR8_PART_IS_DEFINED(ATmega324P) || \ + AVR8_PART_IS_DEFINED(ATmega325) || \ + AVR8_PART_IS_DEFINED(ATmega3250) || \ + AVR8_PART_IS_DEFINED(ATmega3250A) || \ + AVR8_PART_IS_DEFINED(ATmega3250P) || \ + AVR8_PART_IS_DEFINED(ATmega3250PA) || \ + AVR8_PART_IS_DEFINED(ATmega325A) || \ + AVR8_PART_IS_DEFINED(ATmega325P) || \ + AVR8_PART_IS_DEFINED(ATmega325PA) || \ + AVR8_PART_IS_DEFINED(ATmega329) || \ + AVR8_PART_IS_DEFINED(ATmega3290) || \ + AVR8_PART_IS_DEFINED(ATmega3290A) || \ + AVR8_PART_IS_DEFINED(ATmega3290P) || \ + AVR8_PART_IS_DEFINED(ATmega3290PA) || \ + AVR8_PART_IS_DEFINED(ATmega329A) || \ + AVR8_PART_IS_DEFINED(ATmega32M1) || \ + AVR8_PART_IS_DEFINED(ATmega32U2) || \ + AVR8_PART_IS_DEFINED(ATmega32U4) || \ + AVR8_PART_IS_DEFINED(ATmega48P) || \ + AVR8_PART_IS_DEFINED(ATmega644P) || \ + AVR8_PART_IS_DEFINED(ATmega645) || \ + AVR8_PART_IS_DEFINED(ATmega6450) || \ + AVR8_PART_IS_DEFINED(ATmega6450A) || \ + AVR8_PART_IS_DEFINED(ATmega6450P) || \ + AVR8_PART_IS_DEFINED(ATmega645A) || \ + AVR8_PART_IS_DEFINED(ATmega645P) || \ + AVR8_PART_IS_DEFINED(ATmega649) || \ + AVR8_PART_IS_DEFINED(ATmega6490) || \ + AVR8_PART_IS_DEFINED(ATmega6490A) || \ + AVR8_PART_IS_DEFINED(ATmega6490P) || \ + AVR8_PART_IS_DEFINED(ATmega649A) || \ + AVR8_PART_IS_DEFINED(ATmega649P) || \ + AVR8_PART_IS_DEFINED(ATmega64M1) || \ + AVR8_PART_IS_DEFINED(ATmega64RFA2) || \ + AVR8_PART_IS_DEFINED(ATmega8) || \ + AVR8_PART_IS_DEFINED(ATmega8515) || \ + AVR8_PART_IS_DEFINED(ATmega8535) || \ + AVR8_PART_IS_DEFINED(ATmega88P) || \ + AVR8_PART_IS_DEFINED(ATmega8A) || \ + AVR8_PART_IS_DEFINED(ATmega8U2) \ + ) + +/** Unspecified group */ +#define MEGA_UNSPECIFIED (MEGA_XX_UN0 || MEGA_XX_UN1 || MEGA_XX_UN2 || \ + MEGA_UNCATEGORIZED) + +/** @} */ + +/** megaAVR product line */ +#define MEGA (MEGA_XX0_1 || MEGA_XX4 || MEGA_XX8 || MEGA_XX || MEGA_RF || \ + MEGA_UNSPECIFIED) + +/** @} */ + +/** + * \defgroup sam_part_macros_group SAM parts + * @{ + */ + +/** + * \name SAM3S series + * @{ + */ +#define SAM3S1 ( \ + SAM_PART_IS_DEFINED(SAM3S1A) || \ + SAM_PART_IS_DEFINED(SAM3S1B) || \ + SAM_PART_IS_DEFINED(SAM3S1C) \ + ) + +#define SAM3S2 ( \ + SAM_PART_IS_DEFINED(SAM3S2A) || \ + SAM_PART_IS_DEFINED(SAM3S2B) || \ + SAM_PART_IS_DEFINED(SAM3S2C) \ + ) + +#define SAM3S4 ( \ + SAM_PART_IS_DEFINED(SAM3S4A) || \ + SAM_PART_IS_DEFINED(SAM3S4B) || \ + SAM_PART_IS_DEFINED(SAM3S4C) \ + ) + +#define SAM3S8 ( \ + SAM_PART_IS_DEFINED(SAM3S8B) || \ + SAM_PART_IS_DEFINED(SAM3S8C) \ + ) + +#define SAM3SD8 ( \ + SAM_PART_IS_DEFINED(SAM3SD8B) || \ + SAM_PART_IS_DEFINED(SAM3SD8C) \ + ) +/** @} */ + +/** + * \name SAM3U series + * @{ + */ +#define SAM3U1 ( \ + SAM_PART_IS_DEFINED(SAM3U1C) || \ + SAM_PART_IS_DEFINED(SAM3U1E) \ + ) + +#define SAM3U2 ( \ + SAM_PART_IS_DEFINED(SAM3U2C) || \ + SAM_PART_IS_DEFINED(SAM3U2E) \ + ) + +#define SAM3U4 ( \ + SAM_PART_IS_DEFINED(SAM3U4C) || \ + SAM_PART_IS_DEFINED(SAM3U4E) \ + ) +/** @} */ + +/** + * \name SAM3N series + * @{ + */ +#define SAM3N00 ( \ + SAM_PART_IS_DEFINED(SAM3N00A) || \ + SAM_PART_IS_DEFINED(SAM3N00B) \ + ) + +#define SAM3N0 ( \ + SAM_PART_IS_DEFINED(SAM3N0A) || \ + SAM_PART_IS_DEFINED(SAM3N0B) || \ + SAM_PART_IS_DEFINED(SAM3N0C) \ + ) + +#define SAM3N1 ( \ + SAM_PART_IS_DEFINED(SAM3N1A) || \ + SAM_PART_IS_DEFINED(SAM3N1B) || \ + SAM_PART_IS_DEFINED(SAM3N1C) \ + ) + +#define SAM3N2 ( \ + SAM_PART_IS_DEFINED(SAM3N2A) || \ + SAM_PART_IS_DEFINED(SAM3N2B) || \ + SAM_PART_IS_DEFINED(SAM3N2C) \ + ) + +#define SAM3N4 ( \ + SAM_PART_IS_DEFINED(SAM3N4A) || \ + SAM_PART_IS_DEFINED(SAM3N4B) || \ + SAM_PART_IS_DEFINED(SAM3N4C) \ + ) +/** @} */ + +/** + * \name SAM3X series + * @{ + */ +#define SAM3X4 ( \ + SAM_PART_IS_DEFINED(SAM3X4C) || \ + SAM_PART_IS_DEFINED(SAM3X4E) \ + ) + +#define SAM3X8 ( \ + SAM_PART_IS_DEFINED(SAM3X8C) || \ + SAM_PART_IS_DEFINED(SAM3X8E) || \ + SAM_PART_IS_DEFINED(SAM3X8H) \ + ) +/** @} */ + +/** + * \name SAM3A series + * @{ + */ +#define SAM3A4 ( \ + SAM_PART_IS_DEFINED(SAM3A4C) \ + ) + +#define SAM3A8 ( \ + SAM_PART_IS_DEFINED(SAM3A8C) \ + ) +/** @} */ + +/** + * \name SAM4S series + * @{ + */ +#define SAM4S2 ( \ + SAM_PART_IS_DEFINED(SAM4S2A) || \ + SAM_PART_IS_DEFINED(SAM4S2B) || \ + SAM_PART_IS_DEFINED(SAM4S2C) \ + ) + +#define SAM4S4 ( \ + SAM_PART_IS_DEFINED(SAM4S4A) || \ + SAM_PART_IS_DEFINED(SAM4S4B) || \ + SAM_PART_IS_DEFINED(SAM4S4C) \ + ) + +#define SAM4S8 ( \ + SAM_PART_IS_DEFINED(SAM4S8B) || \ + SAM_PART_IS_DEFINED(SAM4S8C) \ + ) + +#define SAM4S16 ( \ + SAM_PART_IS_DEFINED(SAM4S16B) || \ + SAM_PART_IS_DEFINED(SAM4S16C) \ + ) + +#define SAM4SA16 ( \ + SAM_PART_IS_DEFINED(SAM4SA16B) || \ + SAM_PART_IS_DEFINED(SAM4SA16C) \ + ) + +#define SAM4SD16 ( \ + SAM_PART_IS_DEFINED(SAM4SD16B) || \ + SAM_PART_IS_DEFINED(SAM4SD16C) \ + ) + +#define SAM4SD32 ( \ + SAM_PART_IS_DEFINED(SAM4SD32B) || \ + SAM_PART_IS_DEFINED(SAM4SD32C) \ + ) +/** @} */ + +/** + * \name SAM4L series + * @{ + */ +#define SAM4LS ( \ + SAM_PART_IS_DEFINED(SAM4LS2A) || \ + SAM_PART_IS_DEFINED(SAM4LS2B) || \ + SAM_PART_IS_DEFINED(SAM4LS2C) || \ + SAM_PART_IS_DEFINED(SAM4LS4A) || \ + SAM_PART_IS_DEFINED(SAM4LS4B) || \ + SAM_PART_IS_DEFINED(SAM4LS4C) || \ + SAM_PART_IS_DEFINED(SAM4LS8A) || \ + SAM_PART_IS_DEFINED(SAM4LS8B) || \ + SAM_PART_IS_DEFINED(SAM4LS8C) \ + ) + +#define SAM4LC ( \ + SAM_PART_IS_DEFINED(SAM4LC2A) || \ + SAM_PART_IS_DEFINED(SAM4LC2B) || \ + SAM_PART_IS_DEFINED(SAM4LC2C) || \ + SAM_PART_IS_DEFINED(SAM4LC4A) || \ + SAM_PART_IS_DEFINED(SAM4LC4B) || \ + SAM_PART_IS_DEFINED(SAM4LC4C) || \ + SAM_PART_IS_DEFINED(SAM4LC8A) || \ + SAM_PART_IS_DEFINED(SAM4LC8B) || \ + SAM_PART_IS_DEFINED(SAM4LC8C) \ + ) +/** @} */ + +/** + * \name SAMD20 series + * @{ + */ +#define SAMD20J ( \ + SAM_PART_IS_DEFINED(SAMD20J14) || \ + SAM_PART_IS_DEFINED(SAMD20J15) || \ + SAM_PART_IS_DEFINED(SAMD20J16) || \ + SAM_PART_IS_DEFINED(SAMD20J14B) || \ + SAM_PART_IS_DEFINED(SAMD20J15B) || \ + SAM_PART_IS_DEFINED(SAMD20J16B) || \ + SAM_PART_IS_DEFINED(SAMD20J17) || \ + SAM_PART_IS_DEFINED(SAMD20J18) \ + ) + +#define SAMD20G ( \ + SAM_PART_IS_DEFINED(SAMD20G14) || \ + SAM_PART_IS_DEFINED(SAMD20G15) || \ + SAM_PART_IS_DEFINED(SAMD20G16) || \ + SAM_PART_IS_DEFINED(SAMD20G14B) || \ + SAM_PART_IS_DEFINED(SAMD20G15B) || \ + SAM_PART_IS_DEFINED(SAMD20G16B) || \ + SAM_PART_IS_DEFINED(SAMD20G17) || \ + SAM_PART_IS_DEFINED(SAMD20G17U) || \ + SAM_PART_IS_DEFINED(SAMD20G18) || \ + SAM_PART_IS_DEFINED(SAMD20G18U) \ + ) + +#define SAMD20E ( \ + SAM_PART_IS_DEFINED(SAMD20E14) || \ + SAM_PART_IS_DEFINED(SAMD20E15) || \ + SAM_PART_IS_DEFINED(SAMD20E16) || \ + SAM_PART_IS_DEFINED(SAMD20E14B) || \ + SAM_PART_IS_DEFINED(SAMD20E15B) || \ + SAM_PART_IS_DEFINED(SAMD20E16B) || \ + SAM_PART_IS_DEFINED(SAMD20E17) || \ + SAM_PART_IS_DEFINED(SAMD20E18) \ + ) + +/** @} */ + +/** + * \name SAMD21 series + * @{ + */ +#define SAMD21J ( \ + SAM_PART_IS_DEFINED(SAMD21J15A) || \ + SAM_PART_IS_DEFINED(SAMD21J16A) || \ + SAM_PART_IS_DEFINED(SAMD21J17A) || \ + SAM_PART_IS_DEFINED(SAMD21J18A) || \ + SAM_PART_IS_DEFINED(SAMD21J15B) || \ + SAM_PART_IS_DEFINED(SAMD21J16B) || \ + SAM_PART_IS_DEFINED(SAMD21J17D) \ + ) + +#define SAMD21G ( \ + SAM_PART_IS_DEFINED(SAMD21G15A) || \ + SAM_PART_IS_DEFINED(SAMD21G16A) || \ + SAM_PART_IS_DEFINED(SAMD21G17A) || \ + SAM_PART_IS_DEFINED(SAMD21G17AU) || \ + SAM_PART_IS_DEFINED(SAMD21G18A) || \ + SAM_PART_IS_DEFINED(SAMD21G18AU) || \ + SAM_PART_IS_DEFINED(SAMD21G15B) || \ + SAM_PART_IS_DEFINED(SAMD21G16B) || \ + SAM_PART_IS_DEFINED(SAMD21G15L) || \ + SAM_PART_IS_DEFINED(SAMD21G16L) || \ + SAM_PART_IS_DEFINED(SAMD21G17D) || \ + SAM_PART_IS_DEFINED(SAMD21G17L) \ + ) + +#define SAMD21GXXL ( \ + SAM_PART_IS_DEFINED(SAMD21G15L) || \ + SAM_PART_IS_DEFINED(SAMD21G16L) || \ + SAM_PART_IS_DEFINED(SAMD21G17L) \ + ) + +#define SAMD21E ( \ + SAM_PART_IS_DEFINED(SAMD21E15A) || \ + SAM_PART_IS_DEFINED(SAMD21E16A) || \ + SAM_PART_IS_DEFINED(SAMD21E17A) || \ + SAM_PART_IS_DEFINED(SAMD21E18A) || \ + SAM_PART_IS_DEFINED(SAMD21E15B) || \ + SAM_PART_IS_DEFINED(SAMD21E15BU) || \ + SAM_PART_IS_DEFINED(SAMD21E16B) || \ + SAM_PART_IS_DEFINED(SAMD21E16BU) || \ + SAM_PART_IS_DEFINED(SAMD21E15L) || \ + SAM_PART_IS_DEFINED(SAMD21E16L) || \ + SAM_PART_IS_DEFINED(SAMD21E17D) || \ + SAM_PART_IS_DEFINED(SAMD21E17DU) || \ + SAM_PART_IS_DEFINED(SAMD21E17L) \ + ) + +#define SAMD21EXXL ( \ + SAM_PART_IS_DEFINED(SAMD21E15L) || \ + SAM_PART_IS_DEFINED(SAMD21E16L) || \ + SAM_PART_IS_DEFINED(SAMD21E17L) \ + ) + +/** @} */ + +/** + * \name SAMR21 series + * @{ + */ +#define SAMR21G ( \ + SAM_PART_IS_DEFINED(SAMR21G16A) || \ + SAM_PART_IS_DEFINED(SAMR21G17A) || \ + SAM_PART_IS_DEFINED(SAMR21G18A) \ + ) + +#define SAMR21E ( \ + SAM_PART_IS_DEFINED(SAMR21E16A) || \ + SAM_PART_IS_DEFINED(SAMR21E17A) || \ + SAM_PART_IS_DEFINED(SAMR21E18A) || \ + SAM_PART_IS_DEFINED(SAMR21E19A) \ + ) +/** @} */ + +/** + * \name SAMR30 series + * @{ + */ +#define SAMR30G ( \ + SAM_PART_IS_DEFINED(SAMR30G18A) \ + ) + +#define SAMR30E ( \ + SAM_PART_IS_DEFINED(SAMR30E18A) \ + ) +/** @} */ + +/** + * \name SAMR34 series + * @{ + */ +#define SAMR34J ( \ + SAM_PART_IS_DEFINED(SAMR34J18A) || \ + SAM_PART_IS_DEFINED(SAMR34J17A) || \ + SAM_PART_IS_DEFINED(SAMR34J16A) || \ + SAM_PART_IS_DEFINED(SAMR34J18B) || \ + SAM_PART_IS_DEFINED(SAMR34J17B) || \ + SAM_PART_IS_DEFINED(SAMR34J16B) \ + ) + +/* Group for SAMR34 A variant: SAMR34J [16/17/18]A */ +#define SAMR34JXXA ( \ + SAM_PART_IS_DEFINED(SAMR34J18A) || \ + SAM_PART_IS_DEFINED(SAMR34J17A) || \ + SAM_PART_IS_DEFINED(SAMR34J16A) \ +) +/* Group for SAMR34 B variant: SAMR34J [16/17/18]B */ +#define SAMR34JXXB ( \ + SAM_PART_IS_DEFINED(SAMR34J18B) || \ + SAM_PART_IS_DEFINED(SAMR34J17B) || \ + SAM_PART_IS_DEFINED(SAMR34J16B) \ +) + +/* Group for SAMR35 B variant: SAMR35J [16/17/18]B */ +#define SAMR35J ( \ + SAM_PART_IS_DEFINED(SAMR35J18B) || \ + SAM_PART_IS_DEFINED(SAMR35J17B) || \ + SAM_PART_IS_DEFINED(SAMR35J16B) \ +) + +/* Group for SAMR35 B variant: SAMR35J [16/17/18]B */ +#define SAMR35JXXB ( \ + SAM_PART_IS_DEFINED(SAMR35J18B) || \ + SAM_PART_IS_DEFINED(SAMR35J17B) || \ + SAM_PART_IS_DEFINED(SAMR35J16B) \ +) + +/* Group for SAMR35 B variant: SAMR35J [16/17/18]B */ +#define WLR089U ( \ + SAM_PART_IS_DEFINED(WLR089U0) \ +) + +/* Group for WLR089U variant: SAMR35U [0] */ +#define WLR089U0 ( \ + SAM_PART_IS_DEFINED(WLR089U0) \ +) + +/** + * \name SAMB11 series + * @{ + */ +#define SAMB11G ( \ + SAM_PART_IS_DEFINED(SAMB11G18A) || \ + SAM_PART_IS_DEFINED(SAMB11ZR) \ + ) +#define BTLC1000 ( \ + SAM_PART_IS_DEFINED(BTLC1000WLCSP) \ + ) + +/** @} */ + +/** + * \name SAMD09 series + * @{ + */ +#define SAMD09C ( \ + SAM_PART_IS_DEFINED(SAMD09C13A) \ + ) + +#define SAMD09D ( \ + SAM_PART_IS_DEFINED(SAMD09D14A) \ + ) +/** @} */ + +/** + * \name SAMD10 series + * @{ + */ +#define SAMD10C ( \ + SAM_PART_IS_DEFINED(SAMD10C12A) || \ + SAM_PART_IS_DEFINED(SAMD10C13A) || \ + SAM_PART_IS_DEFINED(SAMD10C14A) \ + ) + +#define SAMD10DS ( \ + SAM_PART_IS_DEFINED(SAMD10D12AS) || \ + SAM_PART_IS_DEFINED(SAMD10D13AS) || \ + SAM_PART_IS_DEFINED(SAMD10D14AS) \ + ) + +#define SAMD10DM ( \ + SAM_PART_IS_DEFINED(SAMD10D12AM) || \ + SAM_PART_IS_DEFINED(SAMD10D13AM) || \ + SAM_PART_IS_DEFINED(SAMD10D14AM) \ + ) + +#define SAMD10DU ( \ + SAM_PART_IS_DEFINED(SAMD10D14AU) \ + ) +/** @} */ + +/** + * \name SAMD11 series + * @{ + */ +#define SAMD11C ( \ + SAM_PART_IS_DEFINED(SAMD11C14A) \ + ) + +#define SAMD11DS ( \ + SAM_PART_IS_DEFINED(SAMD11D14AS) \ + ) + +#define SAMD11DM ( \ + SAM_PART_IS_DEFINED(SAMD11D14AM) \ + ) + +#define SAMD11DU ( \ + SAM_PART_IS_DEFINED(SAMD11D14AU) \ + ) +/** @} */ + +/** + * \name SAML21 series + * @{ + */ +#define SAML21E ( \ + SAM_PART_IS_DEFINED(SAML21E18A) || \ + SAM_PART_IS_DEFINED(SAML21E15B) || \ + SAM_PART_IS_DEFINED(SAML21E16B) || \ + SAM_PART_IS_DEFINED(SAML21E17B) || \ + SAM_PART_IS_DEFINED(SAML21E18B) \ + ) + +#define SAML21G ( \ + SAM_PART_IS_DEFINED(SAML21G18A) || \ + SAM_PART_IS_DEFINED(SAML21G16B) || \ + SAM_PART_IS_DEFINED(SAML21G17B) || \ + SAM_PART_IS_DEFINED(SAML21G18B) \ + ) + +#define SAML21J ( \ + SAM_PART_IS_DEFINED(SAML21J18A) || \ + SAM_PART_IS_DEFINED(SAML21J16B) || \ + SAM_PART_IS_DEFINED(SAML21J17B) || \ + SAM_PART_IS_DEFINED(SAML21J18B) \ + ) + +/* Group for SAML21 A variant: SAML21[E/G/J][18]A */ +#define SAML21XXXA ( \ + SAM_PART_IS_DEFINED(SAML21E18A) || \ + SAM_PART_IS_DEFINED(SAML21G18A) || \ + SAM_PART_IS_DEFINED(SAML21J18A) \ + ) + +/* Group for SAML21 B variant: SAML21[E/G/J][15/16/1718]B */ +#define SAML21XXXB ( \ + SAM_PART_IS_DEFINED(SAML21E15B) || \ + SAM_PART_IS_DEFINED(SAML21E16B) || \ + SAM_PART_IS_DEFINED(SAML21E17B) || \ + SAM_PART_IS_DEFINED(SAML21E18B) || \ + SAM_PART_IS_DEFINED(SAML21G16B) || \ + SAM_PART_IS_DEFINED(SAML21G17B) || \ + SAM_PART_IS_DEFINED(SAML21G18B) || \ + SAM_PART_IS_DEFINED(SAML21J16B) || \ + SAM_PART_IS_DEFINED(SAML21J17B) || \ + SAM_PART_IS_DEFINED(SAML21J18B) \ + ) + +/** @} */ + +/** + * \name SAML22 series + * @{ + */ +#define SAML22N ( \ + SAM_PART_IS_DEFINED(SAML22N16A) || \ + SAM_PART_IS_DEFINED(SAML22N17A) || \ + SAM_PART_IS_DEFINED(SAML22N18A) \ + ) + +#define SAML22G ( \ + SAM_PART_IS_DEFINED(SAML22G16A) || \ + SAM_PART_IS_DEFINED(SAML22G17A) || \ + SAM_PART_IS_DEFINED(SAML22G18A) \ + ) + +#define SAML22J ( \ + SAM_PART_IS_DEFINED(SAML22J16A) || \ + SAM_PART_IS_DEFINED(SAML22J17A) || \ + SAM_PART_IS_DEFINED(SAML22J18A) \ + ) +/** @} */ + +/** + * \name SAMDA1 series + * @{ + */ +#define SAMDA1J ( \ + SAM_PART_IS_DEFINED(SAMDA1J14A) || \ + SAM_PART_IS_DEFINED(SAMDA1J15B) || \ + SAM_PART_IS_DEFINED(SAMDA1J15A) || \ + SAM_PART_IS_DEFINED(SAMDA1J15B) || \ + SAM_PART_IS_DEFINED(SAMDA1J16A) || \ + SAM_PART_IS_DEFINED(SAMDA1J16B) \ + ) + +#define SAMDA1G ( \ + SAM_PART_IS_DEFINED(SAMDA1G14A) || \ + SAM_PART_IS_DEFINED(SAMDA1G14B) || \ + SAM_PART_IS_DEFINED(SAMDA1G15A) || \ + SAM_PART_IS_DEFINED(SAMDA1G15B) || \ + SAM_PART_IS_DEFINED(SAMDA1G16A) || \ + SAM_PART_IS_DEFINED(SAMDA1G16B) \ + ) + +#define SAMDA1E ( \ + SAM_PART_IS_DEFINED(SAMDA1E14A) || \ + SAM_PART_IS_DEFINED(SAMDA1E14B) || \ + SAM_PART_IS_DEFINED(SAMDA1E15A) || \ + SAM_PART_IS_DEFINED(SAMDA1E15B) || \ + SAM_PART_IS_DEFINED(SAMDA1E16A) || \ + SAM_PART_IS_DEFINED(SAMDA1E16B) \ + ) +/** @} */ + +/** + * \name SAMHA1 series + * @{ + */ +#define SAMHA1G ( \ + SAM_PART_IS_DEFINED(SAMHA1G14A) || \ + SAM_PART_IS_DEFINED(SAMHA1G15A) || \ + SAM_PART_IS_DEFINED(SAMHA1G16A) || \ + SAM_PART_IS_DEFINED(SAMHA1G14AB) || \ + SAM_PART_IS_DEFINED(SAMHA1G15AB) || \ + SAM_PART_IS_DEFINED(SAMHA1G16AB) \ + ) + +#define SAMHA1E ( \ + SAM_PART_IS_DEFINED(SAMHA1E14A) || \ + SAM_PART_IS_DEFINED(SAMHA1E15A) || \ + SAM_PART_IS_DEFINED(SAMHA1E16A) || \ + SAM_PART_IS_DEFINED(SAMHA1E14AB) || \ + SAM_PART_IS_DEFINED(SAMHA1E15AB) || \ + SAM_PART_IS_DEFINED(SAMHA1E16AB) \ + ) + +/** @} */ + +/** + * \name SAMHA0 series + * @{ + */ +#define SAMHA0G ( \ + SAM_PART_IS_DEFINED(SAMHA0G14AB) || \ + SAM_PART_IS_DEFINED(SAMHA0G15AB) || \ + SAM_PART_IS_DEFINED(SAMHA0G16AB) \ + ) + +#define SAMHA0E ( \ + SAM_PART_IS_DEFINED(SAMHA0E14AB) || \ + SAM_PART_IS_DEFINED(SAMHA0E15AB) || \ + SAM_PART_IS_DEFINED(SAMHA0E16AB) \ + ) + +/** @} */ + +/** + * \name SAMC20 series + * @{ + */ +#define SAMC20E ( \ + SAM_PART_IS_DEFINED(SAMC20E15A) || \ + SAM_PART_IS_DEFINED(SAMC20E16A) || \ + SAM_PART_IS_DEFINED(SAMC20E17A) || \ + SAM_PART_IS_DEFINED(SAMC20E18A) \ + ) + +#define SAMC20G ( \ + SAM_PART_IS_DEFINED(SAMC20G15A) || \ + SAM_PART_IS_DEFINED(SAMC20G16A) || \ + SAM_PART_IS_DEFINED(SAMC20G17A) || \ + SAM_PART_IS_DEFINED(SAMC20G18A) \ + ) + +#define SAMC20J ( \ + SAM_PART_IS_DEFINED(SAMC20J15A) || \ + SAM_PART_IS_DEFINED(SAMC20J16A) || \ + SAM_PART_IS_DEFINED(SAMC20J17A) || \ + SAM_PART_IS_DEFINED(SAMC20J18A) \ + ) +/** @} */ + +/** + * \name SAMC21 series + * @{ + */ +#define SAMC21E ( \ + SAM_PART_IS_DEFINED(SAMC21E15A) || \ + SAM_PART_IS_DEFINED(SAMC21E16A) || \ + SAM_PART_IS_DEFINED(SAMC21E17A) || \ + SAM_PART_IS_DEFINED(SAMC21E18A) \ + ) + +#define SAMC21G ( \ + SAM_PART_IS_DEFINED(SAMC21G15A) || \ + SAM_PART_IS_DEFINED(SAMC21G16A) || \ + SAM_PART_IS_DEFINED(SAMC21G17A) || \ + SAM_PART_IS_DEFINED(SAMC21G18A) \ + ) + +#define SAMC21J ( \ + SAM_PART_IS_DEFINED(SAMC21J15A) || \ + SAM_PART_IS_DEFINED(SAMC21J16A) || \ + SAM_PART_IS_DEFINED(SAMC21J17A) || \ + SAM_PART_IS_DEFINED(SAMC21J18A) \ + ) +/** @} */ + +/** + * \name SAM4E series + * @{ + */ +#define SAM4E8 ( \ + SAM_PART_IS_DEFINED(SAM4E8C) || \ + SAM_PART_IS_DEFINED(SAM4E8CB) || \ + SAM_PART_IS_DEFINED(SAM4E8E) \ + ) + +#define SAM4E16 ( \ + SAM_PART_IS_DEFINED(SAM4E16C) || \ + SAM_PART_IS_DEFINED(SAM4E16CB) || \ + SAM_PART_IS_DEFINED(SAM4E16E) \ + ) +/** @} */ + +/** + * \name SAM4N series + * @{ + */ +#define SAM4N8 ( \ + SAM_PART_IS_DEFINED(SAM4N8A) || \ + SAM_PART_IS_DEFINED(SAM4N8B) || \ + SAM_PART_IS_DEFINED(SAM4N8C) \ + ) + +#define SAM4N16 ( \ + SAM_PART_IS_DEFINED(SAM4N16B) || \ + SAM_PART_IS_DEFINED(SAM4N16C) \ + ) +/** @} */ + +/** + * \name SAM4C series + * @{ + */ +#define SAM4C4_0 ( \ + SAM_PART_IS_DEFINED(SAM4C4C_0) \ + ) + +#define SAM4C4_1 ( \ + SAM_PART_IS_DEFINED(SAM4C4C_1) \ + ) + +#define SAM4C4 (SAM4C4_0 || SAM4C4_1) + +#define SAM4C8_0 ( \ + SAM_PART_IS_DEFINED(SAM4C8C_0) \ + ) + +#define SAM4C8_1 ( \ + SAM_PART_IS_DEFINED(SAM4C8C_1) \ + ) + +#define SAM4C8 (SAM4C8_0 || SAM4C8_1) + +#define SAM4C16_0 ( \ + SAM_PART_IS_DEFINED(SAM4C16C_0) \ + ) + +#define SAM4C16_1 ( \ + SAM_PART_IS_DEFINED(SAM4C16C_1) \ + ) + +#define SAM4C16 (SAM4C16_0 || SAM4C16_1) + +#define SAM4C32_0 ( \ + SAM_PART_IS_DEFINED(SAM4C32C_0) ||\ + SAM_PART_IS_DEFINED(SAM4C32E_0) \ + ) + +#define SAM4C32_1 ( \ + SAM_PART_IS_DEFINED(SAM4C32C_1) ||\ + SAM_PART_IS_DEFINED(SAM4C32E_1) \ + ) + + +#define SAM4C32 (SAM4C32_0 || SAM4C32_1) + +/** @} */ + +/** + * \name SAM4CM series + * @{ + */ +#define SAM4CMP8_0 ( \ + SAM_PART_IS_DEFINED(SAM4CMP8C_0) \ + ) + +#define SAM4CMP8_1 ( \ + SAM_PART_IS_DEFINED(SAM4CMP8C_1) \ + ) + +#define SAM4CMP8 (SAM4CMP8_0 || SAM4CMP8_1) + +#define SAM4CMP16_0 ( \ + SAM_PART_IS_DEFINED(SAM4CMP16C_0) \ + ) + +#define SAM4CMP16_1 ( \ + SAM_PART_IS_DEFINED(SAM4CMP16C_1) \ + ) + +#define SAM4CMP16 (SAM4CMP16_0 || SAM4CMP16_1) + +#define SAM4CMP32_0 ( \ + SAM_PART_IS_DEFINED(SAM4CMP32C_0) \ + ) + +#define SAM4CMP32_1 ( \ + SAM_PART_IS_DEFINED(SAM4CMP32C_1) \ + ) + +#define SAM4CMP32 (SAM4CMP32_0 || SAM4CMP32_1) + +#define SAM4CMS4_0 ( \ + SAM_PART_IS_DEFINED(SAM4CMS4C_0) \ + ) + +#define SAM4CMS4_1 ( \ + SAM_PART_IS_DEFINED(SAM4CMS4C_1) \ + ) + +#define SAM4CMS4 (SAM4CMS4_0 || SAM4CMS4_1) + +#define SAM4CMS8_0 ( \ + SAM_PART_IS_DEFINED(SAM4CMS8C_0) \ + ) + +#define SAM4CMS8_1 ( \ + SAM_PART_IS_DEFINED(SAM4CMS8C_1) \ + ) + +#define SAM4CMS8 (SAM4CMS8_0 || SAM4CMS8_1) + +#define SAM4CMS16_0 ( \ + SAM_PART_IS_DEFINED(SAM4CMS16C_0) \ + ) + +#define SAM4CMS16_1 ( \ + SAM_PART_IS_DEFINED(SAM4CMS16C_1) \ + ) + +#define SAM4CMS16 (SAM4CMS16_0 || SAM4CMS16_1) + +#define SAM4CMS32_0 ( \ + SAM_PART_IS_DEFINED(SAM4CMS32C_0) \ + ) + +#define SAM4CMS32_1 ( \ + SAM_PART_IS_DEFINED(SAM4CMS32C_1) \ + ) + +#define SAM4CMS32 (SAM4CMS32_0 || SAM4CMS32_1) + +/** @} */ + +/** + * \name SAM4CP series + * @{ + */ +#define SAM4CP16_0 ( \ + SAM_PART_IS_DEFINED(SAM4CP16B_0) \ + ) + +#define SAM4CP16_1 ( \ + SAM_PART_IS_DEFINED(SAM4CP16B_1) \ + ) + +#define SAM4CP16 (SAM4CP16_0 || SAM4CP16_1) +/** @} */ + +/** + * \name SAMG series + * @{ + */ +#define SAMG51 ( \ + SAM_PART_IS_DEFINED(SAMG51G18) \ + ) + +#define SAMG53 ( \ + SAM_PART_IS_DEFINED(SAMG53G19) ||\ + SAM_PART_IS_DEFINED(SAMG53N19) \ + ) + +#define SAMG54 ( \ + SAM_PART_IS_DEFINED(SAMG54G19) ||\ + SAM_PART_IS_DEFINED(SAMG54J19) ||\ + SAM_PART_IS_DEFINED(SAMG54N19) \ + ) + +#define SAMG55 ( \ + SAM_PART_IS_DEFINED(SAMG55G18) ||\ + SAM_PART_IS_DEFINED(SAMG55G19) ||\ + SAM_PART_IS_DEFINED(SAMG55J18) ||\ + SAM_PART_IS_DEFINED(SAMG55J19) ||\ + SAM_PART_IS_DEFINED(SAMG55N19) \ + ) +/** @} */ + +/** + * \name SAMV71 series + * @{ + */ +#define SAMV71J ( \ + SAM_PART_IS_DEFINED(SAMV71J19) || \ + SAM_PART_IS_DEFINED(SAMV71J20) || \ + SAM_PART_IS_DEFINED(SAMV71J21) \ + ) + +#define SAMV71JB ( \ + SAM_PART_IS_DEFINED(SAMV71J19B) || \ + SAM_PART_IS_DEFINED(SAMV71J20B) || \ + SAM_PART_IS_DEFINED(SAMV71J21B) \ + ) + +#define SAMV71N ( \ + SAM_PART_IS_DEFINED(SAMV71N19) || \ + SAM_PART_IS_DEFINED(SAMV71N20) || \ + SAM_PART_IS_DEFINED(SAMV71N21) \ + ) + +#define SAMV71NB ( \ + SAM_PART_IS_DEFINED(SAMV71N19B) || \ + SAM_PART_IS_DEFINED(SAMV71N20B) || \ + SAM_PART_IS_DEFINED(SAMV71N21B) \ + ) + +#define SAMV71Q ( \ + SAM_PART_IS_DEFINED(SAMV71Q19) || \ + SAM_PART_IS_DEFINED(SAMV71Q20) || \ + SAM_PART_IS_DEFINED(SAMV71Q21) \ + ) + +#define SAMV71QB ( \ + SAM_PART_IS_DEFINED(SAMV71Q19B) || \ + SAM_PART_IS_DEFINED(SAMV71Q20B) || \ + SAM_PART_IS_DEFINED(SAMV71Q21B) \ + ) + +/** @} */ + +/** + * \name SAMV70 series + * @{ + */ +#define SAMV70J ( \ + SAM_PART_IS_DEFINED(SAMV70J19) || \ + SAM_PART_IS_DEFINED(SAMV70J20) \ + ) + +#define SAMV70JB ( \ + SAM_PART_IS_DEFINED(SAMV70J19B) || \ + SAM_PART_IS_DEFINED(SAMV70J20B) \ + ) + +#define SAMV70N ( \ + SAM_PART_IS_DEFINED(SAMV70N19) || \ + SAM_PART_IS_DEFINED(SAMV70N20) \ + ) + +#define SAMV70NB ( \ + SAM_PART_IS_DEFINED(SAMV70N19B) || \ + SAM_PART_IS_DEFINED(SAMV70N20B) \ + ) + +#define SAMV70Q ( \ + SAM_PART_IS_DEFINED(SAMV70Q19) || \ + SAM_PART_IS_DEFINED(SAMV70Q20) \ + ) +#define SAMV70QB ( \ + SAM_PART_IS_DEFINED(SAMV70Q19B) || \ + SAM_PART_IS_DEFINED(SAMV70Q20B) \ + ) +/** @} */ + +/** + * \name SAMS70 series + * @{ + */ +#define SAMS70J ( \ + SAM_PART_IS_DEFINED(SAMS70J19) || \ + SAM_PART_IS_DEFINED(SAMS70J20) || \ + SAM_PART_IS_DEFINED(SAMS70J21) \ + ) + +#define SAMS70JB ( \ + SAM_PART_IS_DEFINED(SAMS70J19B) || \ + SAM_PART_IS_DEFINED(SAMS70J20B) || \ + SAM_PART_IS_DEFINED(SAMS70J21B) \ + ) + +#define SAMS70N ( \ + SAM_PART_IS_DEFINED(SAMS70N19) || \ + SAM_PART_IS_DEFINED(SAMS70N20) || \ + SAM_PART_IS_DEFINED(SAMS70N21) \ + ) + +#define SAMS70NB ( \ + SAM_PART_IS_DEFINED(SAMS70N19B) || \ + SAM_PART_IS_DEFINED(SAMS70N20B) || \ + SAM_PART_IS_DEFINED(SAMS70N21B) \ + ) + +#define SAMS70Q ( \ + SAM_PART_IS_DEFINED(SAMS70Q19) || \ + SAM_PART_IS_DEFINED(SAMS70Q20) || \ + SAM_PART_IS_DEFINED(SAMS70Q21) \ + ) + +#define SAMS70QB ( \ + SAM_PART_IS_DEFINED(SAMS70Q19B) || \ + SAM_PART_IS_DEFINED(SAMS70Q20B) || \ + SAM_PART_IS_DEFINED(SAMS70Q21B) \ + ) +/** @} */ + +/** + * \name SAME70 series + * @{ + */ +#define SAME70J ( \ + SAM_PART_IS_DEFINED(SAME70J19) || \ + SAM_PART_IS_DEFINED(SAME70J20) || \ + SAM_PART_IS_DEFINED(SAME70J21) \ + ) + +#define SAME70JB ( \ + SAM_PART_IS_DEFINED(SAME70J19B) || \ + SAM_PART_IS_DEFINED(SAME70J20B) || \ + SAM_PART_IS_DEFINED(SAME70J21B) \ + ) + +#define SAME70N ( \ + SAM_PART_IS_DEFINED(SAME70N19) || \ + SAM_PART_IS_DEFINED(SAME70N20) || \ + SAM_PART_IS_DEFINED(SAME70N21) \ + ) + +#define SAME70NB ( \ + SAM_PART_IS_DEFINED(SAME70N19B) || \ + SAM_PART_IS_DEFINED(SAME70N20B) || \ + SAM_PART_IS_DEFINED(SAME70N21B) \ + ) + +#define SAME70Q ( \ + SAM_PART_IS_DEFINED(SAME70Q19) || \ + SAM_PART_IS_DEFINED(SAME70Q20) || \ + SAM_PART_IS_DEFINED(SAME70Q21) \ + ) + +#define SAME70QB ( \ + SAM_PART_IS_DEFINED(SAME70Q19B) || \ + SAM_PART_IS_DEFINED(SAME70Q20B) || \ + SAM_PART_IS_DEFINED(SAME70Q21B) \ + ) +/** @} */ + +/** + * \name SAM families + * @{ + */ +/** SAM3S Family */ +#define SAM3S (SAM3S1 || SAM3S2 || SAM3S4 || SAM3S8 || SAM3SD8) + +/** SAM3U Family */ +#define SAM3U (SAM3U1 || SAM3U2 || SAM3U4) + +/** SAM3N Family */ +#define SAM3N (SAM3N00 || SAM3N0 || SAM3N1 || SAM3N2 || SAM3N4) + +/** SAM3XA Family */ +#define SAM3XA (SAM3X4 || SAM3X8 || SAM3A4 || SAM3A8) + +/** SAM4S Family */ +#define SAM4S (SAM4S2 || SAM4S4 || SAM4S8 || SAM4S16 || SAM4SA16 || SAM4SD16 || SAM4SD32) + +/** SAM4L Family */ +#define SAM4L (SAM4LS || SAM4LC) + +/** SAMD20 Family */ +#define SAMD20 (SAMD20J || SAMD20G || SAMD20E) + +/** SAMD21 Family */ +#define SAMD21 (SAMD21J || SAMD21G || SAMD21E) + +/** SAMD09 Family */ +#define SAMD09 (SAMD09C || SAMD09D) + +/** SAMD10 Family */ +#define SAMD10 (SAMD10C || SAMD10DS || SAMD10DM || SAMD10DU) + +/** SAMD11 Family */ +#define SAMD11 (SAMD11C || SAMD11DS || SAMD11DM || SAMD11DU) + +/** SAMDA1 Family */ +#define SAMDA1 (SAMDA1J || SAMDA1G || SAMDA1E) + +/** SAMHA1 Family */ +#define SAMHA1 (SAMHA1G || SAMHA1E) + +/** SAMHA0 Family */ +#define SAMHA0 (SAMHA0G || SAMHA0E) + +/** SAMD Family */ +#define SAMD (SAMD20 || SAMD21 || SAMD09 || SAMD10 || SAMD11 || SAMDA1) + +/** SAMR21 Family */ +#define SAMR21 (SAMR21G || SAMR21E) + +/** SAMR30 Family */ +#define SAMR30 (SAMR30G || SAMR30E) + +/** SAMR34 Family */ +#define SAMR34 (SAMR34J) + +/** SAMR35 Family */ +#define SAMR35 (SAMR35J) + +/** SAMR35 Family */ +#define WLR089 (WLR089U) + +/** SAMB11 Family */ +#define SAMB11 (SAMB11G || BTLC1000) + +/** SAML21 Family */ +#define SAML21 (SAML21J || SAML21G || SAML21E) + +/** SAML22 Family */ +#define SAML22 (SAML22J || SAML22G || SAML22N) +/** SAMC20 Family */ +#define SAMC20 (SAMC20J || SAMC20G || SAMC20E) + +/** SAMC21 Family */ +#define SAMC21 (SAMC21J || SAMC21G || SAMC21E) + +/** SAM4E Family */ +#define SAM4E (SAM4E8 || SAM4E16) + +/** SAM4N Family */ +#define SAM4N (SAM4N8 || SAM4N16) + +/** SAM4C Family */ +#define SAM4C_0 (SAM4C4_0 || SAM4C8_0 || SAM4C16_0 || SAM4C32_0) +#define SAM4C_1 (SAM4C4_1 || SAM4C8_1 || SAM4C16_1 || SAM4C32_1) +#define SAM4C (SAM4C4 || SAM4C8 || SAM4C16 || SAM4C32) + +/** SAM4CM Family */ +#define SAM4CM_0 (SAM4CMP8_0 || SAM4CMP16_0 || SAM4CMP32_0 || \ + SAM4CMS4_0 || SAM4CMS8_0 || SAM4CMS16_0 || SAM4CMS32_0) +#define SAM4CM_1 (SAM4CMP8_1 || SAM4CMP16_1 || SAM4CMP32_1 || \ + SAM4CMS4_1 || SAM4CMS8_1 || SAM4CMS16_1 || SAM4CMS32_1) +#define SAM4CM (SAM4CMP8 || SAM4CMP16 || SAM4CMP32 || \ + SAM4CMS4 || SAM4CMS8 || SAM4CMS16 || SAM4CMS32) + +/** SAM4CP Family */ +#define SAM4CP_0 (SAM4CP16_0) +#define SAM4CP_1 (SAM4CP16_1) +#define SAM4CP (SAM4CP16) + +/** SAMG Family */ +#define SAMG (SAMG51 || SAMG53 || SAMG54 || SAMG55) + +/** SAMB Family */ +#define SAMB (SAMB11) + +/** SAMV71 Family */ +#define SAMV71 (SAMV71J || SAMV71N || SAMV71Q || SAMV71JB || SAMV71NB || SAMV71QB) +#define SAMV71B (SAMV71JB || SAMV71NB || SAMV71QB) + +/** SAMV70 Family */ +#define SAMV70 (SAMV70J || SAMV70N || SAMV70Q || SAMV70JB || SAMV70NB || SAMV70QB) +#define SAMV70B (SAMV70JB || SAMV70NB || SAMV70QB) + +/** SAME70 Family */ +#define SAME70 (SAME70J || SAME70N || SAME70Q || SAME70JB || SAME70NB || SAME70QB) +#define SAME70B (SAME70JB || SAME70NB || SAME70QB) + +/** SAMS70 Family */ +#define SAMS70 (SAMS70J || SAMS70N || SAMS70Q || SAMS70JB || SAMS70NB || SAMS70QB) +#define SAMS70B (SAMS70JB || SAMS70NB || SAMS70QB) + +/** SAM0 product line (cortex-m0+) */ +#define SAM0 (SAMD20 || SAMD21 || SAMR21 || SAMD10 || SAMD11 || SAML21 ||\ + SAMDA1 || SAMC20 || SAMC21 || SAML22 || SAMD09 || SAMR30 || SAMHA1 ||\ + SAMHA0 || SAMR34 || SAMR35 || WLR089) + +/** @} */ + +/** SAM product line */ +#define SAM (SAM3S || SAM3U || SAM3N || SAM3XA || SAM4S || SAM4L || SAM4E || \ + SAM0 || SAM4N || SAM4C || SAM4CM || SAM4CP || SAMG || SAMV71 || SAMV70 || SAME70 || SAMS70) + +/** @} */ + +/** @} */ + +/** @} */ + +#endif /* ATMEL_PARTS_H */ diff --git a/src/boards/mcu/samr34/ASF/common2/services/delay/delay.h b/src/boards/mcu/samr34/ASF/common2/services/delay/delay.h new file mode 100644 index 000000000..2b227de64 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/common2/services/delay/delay.h @@ -0,0 +1,91 @@ +/** + * \file + * + * \brief Common Delay Service + * + * Copyright (c) 2013-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#ifndef DELAY_H_INCLUDED +#define DELAY_H_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup group_common_services_delay Busy-Wait Delay Routines + * + * This module provides simple loop-based delay routines for those + * applications requiring a brief wait during execution. Common for + * API ver. 2. + * + * @{ + */ + +#ifdef SYSTICK_MODE +#include "sam0/systick_counter.h" +#endif +#ifdef CYCLE_MODE +#include "sam0/cycle_counter.h" +#endif + +void delay_init(void); + +/** + * \def delay_s + * \brief Delay in at least specified number of seconds. + * \param delay Delay in seconds + */ +#define delay_s(delay) ((delay) ? cpu_delay_s(delay) : cpu_delay_us(1)) + +/** + * \def delay_ms + * \brief Delay in at least specified number of milliseconds. + * \param delay Delay in milliseconds + */ +#define delay_ms(delay) ((delay) ? cpu_delay_ms(delay) : cpu_delay_us(1)) + +/** + * \def delay_us + * \brief Delay in at least specified number of microseconds. + * \param delay Delay in microseconds + */ +#define delay_us(delay) ((delay) ? cpu_delay_us(delay) : cpu_delay_us(1)) + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* DELAY_H_INCLUDED */ diff --git a/src/boards/mcu/samr34/ASF/common2/services/delay/sam0/systick_counter.c b/src/boards/mcu/samr34/ASF/common2/services/delay/sam0/systick_counter.c new file mode 100644 index 000000000..495dc48cb --- /dev/null +++ b/src/boards/mcu/samr34/ASF/common2/services/delay/sam0/systick_counter.c @@ -0,0 +1,86 @@ +/** + * \file + * + * \brief ARM functions for busy-wait delay loops + * + * Copyright (c) 2014-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#include "delay.h" + +/** + * Value used to calculate ms delay. Default to be used with a 8MHz clock; + */ +static uint32_t cycles_per_ms = 8000000UL / 1000; +static uint32_t cycles_per_us = 8000000UL / 1000000; + +/** + * \brief Initialize the delay driver. + * + * This must be called during start up to initialize the delay routine with + * the current used main clock. It must run any time the main CPU clock is changed. + */ +void delay_init(void) +{ + cycles_per_ms = system_gclk_gen_get_hz(0); + cycles_per_ms /= 1000; + cycles_per_us = cycles_per_ms / 1000; + + SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk; +} + +/** + * \brief Delay loop to delay at least n number of microseconds + * + * \param n Number of microseconds to wait + */ +void delay_cycles_us( + uint32_t n) +{ + while (n--) { + /* Devide up to blocks of 10u */ + delay_cycles(cycles_per_us); + } +} + +/** + * \brief Delay loop to delay at least n number of milliseconds + * + * \param n Number of milliseconds to wait + */ +void delay_cycles_ms( + uint32_t n) +{ + while (n--) { + /* Devide up to blocks of 1ms */ + delay_cycles(cycles_per_ms); + } +} diff --git a/src/boards/mcu/samr34/ASF/common2/services/delay/sam0/systick_counter.h b/src/boards/mcu/samr34/ASF/common2/services/delay/sam0/systick_counter.h new file mode 100644 index 000000000..903908d29 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/common2/services/delay/sam0/systick_counter.h @@ -0,0 +1,103 @@ +/** + * \file + * + * \brief ARM functions for busy-wait delay loops + * + * Copyright (c) 2014-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#ifndef CYCLE_COUNTER_H_INCLUDED +#define CYCLE_COUNTER_H_INCLUDED + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \name Convenience functions for busy-wait delay loops + * + * @{ + */ + +/** + * \brief Delay loop to delay n number of cycles + * Delay program execution for at least the specified number of CPU cycles. + * + * \param n Number of cycles to delay + */ +static inline void delay_cycles( + const uint32_t n) +{ + if (n > 0) { + SysTick->LOAD = n; + SysTick->VAL = 0; + + while (!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk)) { + }; + } +} + +void delay_cycles_us(uint32_t n); + +void delay_cycles_ms(uint32_t n); + +/** + * \brief Delay program execution for at least the specified number of microseconds. + * + * \param delay number of microseconds to wait + */ +#define cpu_delay_us(delay) delay_cycles_us(delay) + +/** + * \brief Delay program execution for at least the specified number of milliseconds. + * + * \param delay number of milliseconds to wait + */ +#define cpu_delay_ms(delay) delay_cycles_ms(delay) + +/** + * \brief Delay program execution for at least the specified number of seconds. + * + * \param delay number of seconds to wait + */ +#define cpu_delay_s(delay) delay_cycles_ms(1000 * delay) + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* CYCLE_COUNTER_H_INCLUDED */ diff --git a/src/boards/mcu/samr34/ASF/sam0/boards/samr34_xplained_pro/board_init.c b/src/boards/mcu/samr34/ASF/sam0/boards/samr34_xplained_pro/board_init.c new file mode 100644 index 000000000..311af571a --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/boards/samr34_xplained_pro/board_init.c @@ -0,0 +1,80 @@ +/** + * \file + * + * \brief SAM R34 Xplained Pro board initialization + * + * Copyright (c) 2016-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#include +#include +#include +#include + +#if defined(__GNUC__) +void board_init(void) WEAK __attribute__((alias("system_board_init"))); +#elif defined(__ICCARM__) +void board_init(void); +# pragma weak board_init=system_board_init +#endif + +void system_board_init(void) +{ + struct port_config pin_conf; + port_get_config_defaults(&pin_conf); + + /* Configure LEDs as outputs, turn them off */ + pin_conf.direction = PORT_PIN_DIR_OUTPUT; + port_pin_set_config(LED_0_PIN, &pin_conf); + port_pin_set_output_level(LED_0_PIN, LED_0_INACTIVE); + + /* Configure LEDs as outputs, turn them off */ + pin_conf.direction = PORT_PIN_DIR_OUTPUT; + port_pin_set_config(LED_1_PIN, &pin_conf); + port_pin_set_output_level(LED_1_PIN, LED_1_INACTIVE); +#ifdef RFSWITCH_ENABLE + /* Configure RFSWITCH as output */ + pin_conf.direction = PORT_PIN_DIR_OUTPUT; + port_pin_set_config(RF_SWITCH_PIN, &pin_conf); + port_pin_set_output_level(RF_SWITCH_PIN, RF_SWITCH_INACTIVE); +#endif + +#ifdef TCXO_ENABLE + /* Configure TXPO PWR as output */ + pin_conf.direction = PORT_PIN_DIR_OUTPUT; + port_pin_set_config(TCXO_PWR_PIN, &pin_conf); + port_pin_set_output_level(TCXO_PWR_PIN, TCXO_PWR_INACTIVE); +#endif + /* Set buttons as inputs */ + pin_conf.direction = PORT_PIN_DIR_INPUT; + pin_conf.input_pull = PORT_PIN_PULL_UP; + port_pin_set_config(BUTTON_0_PIN, &pin_conf); + +} diff --git a/src/boards/mcu/samr34/ASF/sam0/boards/samr34_xplained_pro/samr34_xplained_pro.h b/src/boards/mcu/samr34/ASF/sam0/boards/samr34_xplained_pro/samr34_xplained_pro.h new file mode 100644 index 000000000..94f4196ea --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/boards/samr34_xplained_pro/samr34_xplained_pro.h @@ -0,0 +1,532 @@ +/** + * \file + * + * \brief SAM R34 Xplained Pro board definition + * + * Copyright (c) 2016-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#ifndef SAMR34_XPLAINED_PRO_H_INCLUDED +#define SAMR34_XPLAINED_PRO_H_INCLUDED + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \ingroup group_common_boards + * \defgroup samr34_xplained_pro_group SAM R34 Xplained Pro board + * + * @{ + */ + +void system_board_init(void); + +/** + * \defgroup samr34xplained_pro_features_group Features + * + * Symbols that describe features and capabilities of the board. + * + * @{ + */ + +/** Name string macro */ +#define BOARD_NAME "SAMR34_XPLAINED_PRO" + +/** \name Resonator definitions + * @{ */ +#define BOARD_FREQ_SLCK_XTAL (32768U) +#define BOARD_FREQ_SLCK_BYPASS (32768U) +#define BOARD_FREQ_MAINCK_XTAL 0 /* Not Mounted */ +#define BOARD_FREQ_MAINCK_BYPASS 0 /* Not Mounted */ +#define BOARD_MCK CHIP_FREQ_CPU_MAX +#define BOARD_OSC_STARTUP_US 15625 +/** @} */ + +/** \name LED0 definitions + * @{ */ +#define LED0_PIN PIN_PA19 +#define LED0_ACTIVE false +#define LED0_INACTIVE !LED0_ACTIVE +/** @} */ + +/** \name LED1 definitions + * @{ */ +#define LED1_PIN PIN_PA18 +#define LED1_ACTIVE false +#define LED1_INACTIVE !LED1_ACTIVE +/** @} */ + +/** \name SW0 definitions + * @{ */ +#define SW0_PIN PIN_PA28 +#define SW0_ACTIVE false +#define SW0_INACTIVE !SW0_ACTIVE +#define SW0_EIC_PIN PIN_PA28 +#define SW0_EIC_MUX MUX_PA28A_EIC_EXTINT8 +#define SW0_EIC_PINMUX PINMUX_PA28A_EIC_EXTINT8 +#define SW0_EIC_LINE 8 +/** @} */ + +/** \name RF SWITCH definitions + * @{ */ +#define RF_SWITCH_PIN PIN_PA13 +#define RF_SWITCH_ACTIVE true +#define RF_SWITCH_INACTIVE !RF_SWITCH_ACTIVE +/** @} */ + +/** \name TCXO PWR Pin definitions + * @{ */ +#define TCXO_PWR_PIN PIN_PA09 +#define TCXO_PWR_ACTIVE true +#define TCXO_PWR_INACTIVE !TCXO_PWR_ACTIVE +/** @} */ + + +/** + * \name LED #0 definitions + * + * Wrapper macros for LED0, to ensure common naming across all Xplained Pro + * boards. + * + * @{ */ +#define LED_0_NAME "LED0 (yellow)" +#define LED_0_PIN LED0_PIN +#define LED_0_ACTIVE LED0_ACTIVE +#define LED_0_INACTIVE LED0_INACTIVE +#define LED0_GPIO LED0_PIN +#define LED0 LED0_PIN + +#define LED_0_PWM3CTRL_MODULE TCC0 +#define LED_0_PWM3CTRL_CHANNEL 3 +#define LED_0_PWM3CTRL_OUTPUT 3 +#define LED_0_PWM3CTRL_PIN PIN_PA19F_TCC0_WO3 +#define LED_0_PWM3CTRL_MUX MUX_PA19F_TCC0_WO3 +#define LED_0_PWM3CTRL_PINMUX PINMUX_PA19F_TCC0_WO3 +/** @} */ + +/** + * \name LED #1 definitions + * + * Wrapper macros for LED1, to ensure common naming across all Xplained Pro + * boards. + * + * @{ */ +#define LED_1_NAME "LED1 (Green)" +#define LED_1_PIN LED1_PIN +#define LED_1_ACTIVE LED1_ACTIVE +#define LED_1_INACTIVE LED1_INACTIVE +#define LED1_GPIO LED1_PIN +#define LED1 LED1_PIN + +#define LED_1_PWM2CTRL_MODULE TCC0 +#define LED_1_PWM2CTRL_CHANNEL 2 +#define LED_1_PWM2CTRL_OUTPUT 2 +#define LED_1_PWM2CTRL_PIN PINMUX_PA18F_TCC0_WO2 +#define LED_1_PWM2CTRL_MUX MUX_PA18F_TCC0_WO2 +#define LED_1_PWM2CTRL_PINMUX PINMUX_PA18F_TCC0_WO2 +/** @} */ + +/** Number of on-board LEDs */ +#define LED_COUNT 2 + + +/** + * \name Button #0 definitions + * + * Wrapper macros for SW0, to ensure common naming across all Xplained Pro + * boards. + * + * @{ */ +#define BUTTON_0_NAME "SW0" +#define BUTTON_0_PIN SW0_PIN +#define BUTTON_0_ACTIVE SW0_ACTIVE +#define BUTTON_0_INACTIVE SW0_INACTIVE +#define BUTTON_0_EIC_PIN SW0_EIC_PIN +#define BUTTON_0_EIC_MUX SW0_EIC_MUX +#define BUTTON_0_EIC_PINMUX SW0_EIC_PINMUX +#define BUTTON_0_EIC_LINE SW0_EIC_LINE +/** @} */ + +/** Number of on-board buttons */ +#define BUTTON_COUNT 1 + +/** \name Extension header #1 pin definitions + * @{ + */ +#define EXT1_PIN_3 PIN_PA06 +#define EXT1_PIN_4 PIN_PA07 +#define EXT1_PIN_5 PIN_PA08 +#define EXT1_PIN_6 PIN_PA28 +#define EXT1_PIN_7 PIN_PA18 +#define EXT1_PIN_8 PIN_PA19 +#define EXT1_PIN_9 PIN_PA22 +#define EXT1_PIN_10 PIN_PA15 +#define EXT1_PIN_11 PIN_PA16 +#define EXT1_PIN_12 PIN_PA17 +#define EXT1_PIN_13 PIN_PA05 +#define EXT1_PIN_14 PIN_PA04 +#define EXT1_PIN_15 PIN_PA23 +#define EXT1_PIN_16 PIN_PB22 +#define EXT1_PIN_17 PIN_PB02 +#define EXT1_PIN_18 PIN_PB23 +/** @} */ + +/** \name Extension header #1 pin definitions by function + * @{ + */ +#define EXT1_PIN_ADC_0 EXT1_PIN_3 +#define EXT1_PIN_ADC_1 EXT1_PIN_4 +#define EXT1_PIN_GPIO_0 EXT1_PIN_5 +#define EXT1_PIN_GPIO_1 EXT1_PIN_6 +#define EXT1_PIN_PWM_0 EXT1_PIN_7 +#define EXT1_PIN_PWM_1 EXT1_PIN_8 +#define EXT1_PIN_IRQ EXT1_PIN_9 +#define EXT1_PIN_I2C_SDA EXT1_PIN_11 +#define EXT1_PIN_I2C_SCL EXT1_PIN_12 +#define EXT1_PIN_UART_RX EXT1_PIN_13 +#define EXT1_PIN_UART_TX EXT1_PIN_14 +#define EXT1_PIN_SPI_SS_1 EXT1_PIN_10 +#define EXT1_PIN_SPI_SS_0 EXT1_PIN_15 +#define EXT1_PIN_SPI_MOSI EXT1_PIN_16 +#define EXT1_PIN_SPI_MISO EXT1_PIN_17 +#define EXT1_PIN_SPI_SCK EXT1_PIN_18 +/** @} */ + +/** \name Extension header #1 ADC definitions + * @{ + */ +#define EXT1_ADC_MODULE ADC +#define EXT1_ADC_6_CHANNEL 6 +#define EXT1_ADC_6_PIN PIN_PA06B_ADC_AIN6 +#define EXT1_ADC_6_MUX MUX_PA06B_ADC_AIN6 +#define EXT1_ADC_6_PINMUX PINMUX_PA06B_ADC_AIN6 +#define EXT1_ADC_7_CHANNEL 7 +#define EXT1_ADC_7_PIN PIN_PA07B_ADC_AIN7 +#define EXT1_ADC_7_MUX MUX_PA07B_ADC_AIN7 +#define EXT1_ADC_7_PINMUX PINMUX_PA07B_ADC_AIN7 +/** @} */ + +/** \name Extension header #1 PWM definitions + * @{ + */ +#define EXT1_PWM_MODULE TCC0 +#define EXT1_PWM_0_CHANNEL 2 +#define EXT1_PWM_0_PIN PIN_PA18F_TCC0_WO2 +#define EXT1_PWM_0_MUX MUX_PA18F_TCC0_WO2 +#define EXT1_PWM_0_PINMUX PINMUX_PA18F_TCC0_WO2 +#define EXT1_PWM_1_CHANNEL 3 +#define EXT1_PWM_1_PIN PIN_PA19F_TCC0_WO3 +#define EXT1_PWM_1_MUX MUX_PA19F_TCC0_WO3 +#define EXT1_PWM_1_PINMUX PINMUX_PA19F_TCC0_WO3 +/** @} */ + +/** \name Extension header #1 IRQ/External interrupt definitions + * @{ + */ +#define EXT1_IRQ_MODULE EIC +#define EXT1_IRQ_INPUT 6 +#define EXT1_IRQ_PIN PIN_PA22A_EIC_EXTINT6 +#define EXT1_IRQ_MUX MUX_PA22A_EIC_EXTINT6 +#define EXT1_IRQ_PINMUX PINMUX_PA22A_EIC_EXTINT6 +/** @} */ + +/** \name Extension header #1 I2C definitions + * @{ + */ +#define EXT1_I2C_MODULE SERCOM1 +#define EXT1_I2C_SERCOM_PINMUX_PAD0 PINMUX_PA16C_SERCOM1_PAD0 +#define EXT1_I2C_SERCOM_PINMUX_PAD1 PINMUX_PA17C_SERCOM1_PAD1 +#define EXT1_I2C_SERCOM_DMAC_ID_TX SERCOM1_DMAC_ID_TX +#define EXT1_I2C_SERCOM_DMAC_ID_RX SERCOM1_DMAC_ID_RX +/** @} */ + +/** \name Extension header #1 UART definitions + * @{ + */ +#define EXT1_UART_MODULE SERCOM0 +#define EXT1_UART_SERCOM_MUX_SETTING USART_RX_1_TX_0_XCK_1 +#define EXT1_UART_SERCOM_PINMUX_PAD0 PINMUX_PA04D_SERCOM0_PAD0 +#define EXT1_UART_SERCOM_PINMUX_PAD1 PINMUX_PA05D_SERCOM0_PAD1 +#define EXT1_UART_SERCOM_PINMUX_PAD2 PINMUX_UNUSED +#define EXT1_UART_SERCOM_PINMUX_PAD3 PINMUX_UNUSED +#define EXT1_UART_SERCOM_DMAC_ID_TX SERCOM0_DMAC_ID_TX +#define EXT1_UART_SERCOM_DMAC_ID_RX SERCOM0_DMAC_ID_RX + +#define EXT1_UART_SERCOM_PIN_PAD0 PIN_PA04D_SERCOM0_PAD0 +#define EXT1_UART_SERCOM_PIN_PAD1 PIN_PA05D_SERCOM0_PAD1 +/** @} */ + +/** \name Extension header #1 SPI definitions + * @{ + */ +#define EXT1_SPI_MODULE SERCOM5 +#define EXT1_SPI_SERCOM_MUX_SETTING SPI_SIGNAL_MUX_SETTING_E +#define EXT1_SPI_SERCOM_PINMUX_PAD0 PINMUX_PB02D_SERCOM5_PAD0 +#define EXT1_SPI_SERCOM_PINMUX_PAD1 PINMUX_PA23D_SERCOM5_PAD1 +#define EXT1_SPI_SERCOM_PINMUX_PAD2 PINMUX_PB22D_SERCOM5_PAD2 +#define EXT1_SPI_SERCOM_PINMUX_PAD3 PINMUX_PB23D_SERCOM5_PAD3 +#define EXT1_SPI_SERCOM_DMAC_ID_TX SERCOM5_DMAC_ID_TX +#define EXT1_SPI_SERCOM_DMAC_ID_RX SERCOM5_DMAC_ID_RX +/** @} */ + +/** \name Extension header #3 pin definitions + * @{ + */ +#define EXT3_PIN_5 PIN_PA27 +#define EXT3_PIN_10 PIN_PA08 +#define EXT3_PIN_11 PIN_PA16 +#define EXT3_PIN_12 PIN_PA17 +#define EXT3_PIN_15 PIN_PA14 +#define EXT3_PIN_16 PIN_PB22 +#define EXT3_PIN_17 PIN_PB02 +#define EXT3_PIN_18 PIN_PB23 +/** @} */ + +/** \name Extension header #3 pin definitions by function + * @{ + */ +#define EXT3_PIN_GPIO_1 EXT3_PIN_5 +#define EXT3_PIN_I2C_SDA EXT3_PIN_11 +#define EXT3_PIN_I2C_SCL EXT3_PIN_12 +#define EXT3_PIN_SPI_SS_1 EXT3_PIN_10 +#define EXT3_PIN_SPI_SS_0 EXT3_PIN_15 +#define EXT3_PIN_SPI_MOSI EXT3_PIN_16 +#define EXT3_PIN_SPI_MISO EXT3_PIN_17 +#define EXT3_PIN_SPI_SCK EXT3_PIN_18 +/** @} */ + + +/** \name Extension header #3 IRQ/External interrupt definitions + * @{ + */ +#define EXT3_IRQ_MODULE EIC +#define EXT3_IRQ_INPUT 0 +#define EXT3_IRQ_PIN PIN_PA16A_EIC_EXTINT0 +#define EXT3_IRQ_MUX MUX_PA16A_EIC_EXTINT0 +#define EXT3_IRQ_PINMUX PINMUX_PA16A_EIC_EXTINT0 +/** @} */ + +/** \name Extension header #3 I2C definitions + * @{ + */ +#define EXT3_I2C_MODULE SERCOM1 +#define EXT3_I2C_SERCOM_PINMUX_PAD0 PINMUX_PA16C_SERCOM1_PAD0 +#define EXT3_I2C_SERCOM_PINMUX_PAD1 PINMUX_PA17C_SERCOM1_PAD1 +#define EXT3_I2C_SERCOM_DMAC_ID_TX SERCOM1_DMAC_ID_TX +#define EXT3_I2C_SERCOM_DMAC_ID_RX SERCOM1_DMAC_ID_RX +/** @} */ + +/** \name Extension header #3 UART definitions + * @{ + */ +#define EXT3_UART_MODULE SERCOM1 +#define EXT3_UART_SERCOM_MUX_SETTING USART_RX_3_TX_2_XCK_3 +#define EXT3_UART_SERCOM_PINMUX_PAD0 PINMUX_UNUSED +#define EXT3_UART_SERCOM_PINMUX_PAD1 PINMUX_UNUSED +#define EXT3_UART_SERCOM_PINMUX_PAD2 PINMUX_PA18C_SERCOM1_PAD2 +#define EXT3_UART_SERCOM_PINMUX_PAD3 PINMUX_PA19C_SERCOM1_PAD3 +#define EXT3_UART_SERCOM_DMAC_ID_TX SERCOM1_DMAC_ID_TX +#define EXT3_UART_SERCOM_DMAC_ID_RX SERCOM1_DMAC_ID_RX + +/** @} */ + +/** \name Extension header #3 SPI definitions + * @{ + */ +#define EXT3_SPI_MODULE SERCOM5 +#define EXT3_SPI_SERCOM_MUX_SETTING SPI_SIGNAL_MUX_SETTING_E +#define EXT3_SPI_SERCOM_PINMUX_PAD0 PINMUX_PB02D_SERCOM5_PAD0 +#define EXT3_SPI_SERCOM_PINMUX_PAD1 PINMUX_UNUSED +#define EXT3_SPI_SERCOM_PINMUX_PAD2 PINMUX_PB22D_SERCOM5_PAD2 +#define EXT3_SPI_SERCOM_PINMUX_PAD3 PINMUX_PB23D_SERCOM5_PAD3 +#define EXT3_SPI_SERCOM_DMAC_ID_TX SERCOM5_DMAC_ID_TX +#define EXT3_SPI_SERCOM_DMAC_ID_RX SERCOM5_DMAC_ID_RX +/** @} */ + +/** \name Embedded debugger I2C interface definitions + * @{ + */ +#define EDBG_I2C_MODULE SERCOM1 +#define EDBG_I2C_SERCOM_PINMUX_PAD0 PINMUX_PA16C_SERCOM1_PAD0 +#define EDBG_I2C_SERCOM_PINMUX_PAD1 PINMUX_PA17C_SERCOM1_PAD1 +#define EDBG_I2C_SERCOM_DMAC_ID_TX SERCOM1_DMAC_ID_TX +#define EDBG_I2C_SERCOM_DMAC_ID_RX SERCOM1_DMAC_ID_RX +/** @} */ + +/** \name Embedded debugger SPI interface definitions + * @{ + */ +#define EDBG_SPI_MODULE SERCOM5 +#define EDBG_SPI_SERCOM_MUX_SETTING SPI_SIGNAL_MUX_SETTING_E +#define EDBG_SPI_SERCOM_PINMUX_PAD0 PINMUX_PB02D_SERCOM5_PAD0 +#define EDBG_SPI_SERCOM_PINMUX_PAD1 PINMUX_UNUSED +#define EDBG_SPI_SERCOM_PINMUX_PAD2 PINMUX_PB22D_SERCOM5_PAD2 +#define EDBG_SPI_SERCOM_PINMUX_PAD3 PINMUX_PB23D_SERCOM5_PAD3 +#define EDBG_SPI_SERCOM_DMAC_ID_TX SERCOM5_DMAC_ID_TX +#define EDBG_SPI_SERCOM_DMAC_ID_RX SERCOM5_DMAC_ID_RX +/** @} */ + +/** \name Embedded debugger CDC Gateway USART interface definitions + * @{ + */ +#define EDBG_CDC_MODULE SERCOM0 +#define EDBG_CDC_SERCOM_MUX_SETTING USART_RX_1_TX_0_XCK_1 +#define EDBG_CDC_SERCOM_PINMUX_PAD0 PINMUX_PA04D_SERCOM0_PAD0 +#define EDBG_CDC_SERCOM_PINMUX_PAD1 PINMUX_PA05D_SERCOM0_PAD1 +#define EDBG_CDC_SERCOM_PINMUX_PAD2 PINMUX_UNUSED +#define EDBG_CDC_SERCOM_PINMUX_PAD3 PINMUX_UNUSED +#define EDBG_CDC_SERCOM_DMAC_ID_TX SERCOM0_DMAC_ID_TX +#define EDBG_CDC_SERCOM_DMAC_ID_RX SERCOM0_DMAC_ID_RX +/** @} */ + +/** \name USB definitions + * @{ + */ +#define USB_ID +#define USB_TARGET_DP_PIN PIN_PA25G_USB_DP +#define USB_TARGET_DP_MUX MUX_PA25G_USB_DP +#define USB_TARGET_DP_PINMUX PINMUX_PA25G_USB_DP +#define USB_TARGET_DM_PIN PIN_PA24G_USB_DM +#define USB_TARGET_DM_MUX MUX_PA24G_USB_DM +#define USB_TARGET_DM_PINMUX PINMUX_PA24G_USB_DM +#define USB_VBUS_PIN PIN_PA07 +#define USB_VBUS_EIC_LINE 7 +#define USB_VBUS_EIC_MUX MUX_PA07A_EIC_EXTINT7 +#define USB_VBUS_EIC_PINMUX PINMUX_PA07A_EIC_EXTINT7 +#define USB_ID_PIN PIN_PA15 +#define USB_ID_EIC_LINE 15 +#define USB_ID_EIC_MUX MUX_PA15A_EIC_EXTINT15 +#define USB_ID_EIC_PINMUX PINMUX_PA15A_EIC_EXTINT15 + +#define SX_RF_SPI SERCOM4 +#define SX_RF_RESET_PIN PIN_PB15 +#define SX_RF_SPI_CS PIN_PB31 +#define SX_RF_SPI_MOSI PIN_PB30 +#define SX_RF_SPI_MISO PIN_PC19 +#define SX_RF_SPI_SCK PIN_PC18 + +#define SX_RF_SPI_SERCOM_MUX_SETTING SPI_SIGNAL_MUX_SETTING_E +#define SX_RF_SPI_SERCOM_PINMUX_PAD0 PINMUX_PC19F_SERCOM4_PAD0 +#define SX_RF_SPI_SERCOM_PINMUX_PAD1 PINMUX_UNUSED +#define SX_RF_SPI_SERCOM_PINMUX_PAD2 PINMUX_PB30F_SERCOM4_PAD2 +#define SX_RF_SPI_SERCOM_PINMUX_PAD3 PINMUX_PC18F_SERCOM4_PAD3 + +#define DIO0_PIN PIN_PB16 +#define DIO0_ACTIVE true +#define DIO0_INACTIVE !DIO0_ACTIVE +#define DIO0_EIC_PIN PIN_PB16A_EIC_EXTINT0 +#define DIO0_EIC_MUX MUX_PB16A_EIC_EXTINT0 +#define DIO0_EIC_PINMUX PINMUX_PB16A_EIC_EXTINT0 +#define DIO0_EIC_LINE 0 + +#define DIO1_PIN PIN_PA11 +#define DIO1_ACTIVE true +#define DIO1_INACTIVE !DIO1_ACTIVE +#define DIO1_EIC_PIN PIN_PA11A_EIC_EXTINT11 +#define DIO1_EIC_MUX MUX_PA11A_EIC_EXTINT11 +#define DIO1_EIC_PINMUX PINMUX_PA11A_EIC_EXTINT11 +#define DIO1_EIC_LINE 11 + +#define DIO2_PIN PIN_PA12 +#define DIO2_ACTIVE true +#define DIO2_INACTIVE !DIO2_ACTIVE +#define DIO2_EIC_PIN PIN_PA12A_EIC_EXTINT12 +#define DIO2_EIC_MUX MUX_PA12A_EIC_EXTINT12 +#define DIO2_EIC_PINMUX PINMUX_PA12A_EIC_EXTINT12 +#define DIO2_EIC_LINE 12 + +#define DIO3_PIN PIN_PB17 +#define DIO3_ACTIVE true +#define DIO3_INACTIVE !DIO3_ACTIVE +#define DIO3_EIC_PIN PIN_PB17A_EIC_EXTINT1 +#define DIO3_EIC_MUX MUX_PB17A_EIC_EXTINT1 +#define DIO3_EIC_PINMUX PINMUX_PB17A_EIC_EXTINT1 +#define DIO3_EIC_LINE 1 + +#define DIO4_PIN PIN_PA10 +#define DIO4_ACTIVE true +#define DIO4_INACTIVE !DIO4_ACTIVE +#define DIO4_EIC_PIN PIN_PA10A_EIC_EXTINT10 +#define DIO4_EIC_MUX MUX_PA10A_EIC_EXTINT10 +#define DIO4_EIC_PINMUX PINMUX_PA10A_EIC_EXTINT10 +#define DIO4_EIC_LINE 10 + +#define DIO5_PIN PIN_PB00 +#define DIO5_ACTIVE true +#define DIO5_INACTIVE !DIO5_ACTIVE +#define DIO5_EIC_PIN PIN_PB00A_EIC_EXTINT0 +#define DIO5_EIC_MUX MUX_PB00A_EIC_EXTINT0 +#define DIO5_EIC_PINMUX PINMUX_PB00A_EIC_EXTINT0 +#define DIO5_EIC_LINE 0 + +#define SX_RF_RESET_HIGH true +#define SX_RF_RESET_LOW !SX_RF_RESET_HIGH + +/** @} */ + +/** + * \brief Turns off the specified LEDs. + * + * \param led_gpio LED to turn off (LEDx_GPIO). + * + * \note The pins of the specified LEDs are set to GPIO output mode. + */ +#define LED_Off(led_gpio) port_pin_set_output_level(led_gpio,true) + +/** + * \brief Turns on the specified LEDs. + * + * \param led_gpio LED to turn on (LEDx_GPIO). + * + * \note The pins of the specified LEDs are set to GPIO output mode. + */ +#define LED_On(led_gpio) port_pin_set_output_level(led_gpio,false) + +/** + * \brief Toggles the specified LEDs. + * + * \param led_gpio LED to toggle (LEDx_GPIO). + * + * \note The pins of the specified LEDs are set to GPIO output mode. + */ +#define LED_Toggle(led_gpio) port_pin_toggle_output_level(led_gpio) + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* SAMR34_XPLAINED_PRO_H_INCLUDED */ diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/adc/adc.h b/src/boards/mcu/samr34/ASF/sam0/drivers/adc/adc.h new file mode 100644 index 000000000..b24fd8180 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/adc/adc.h @@ -0,0 +1,1147 @@ +/** + * \file + * + * \brief SAM Peripheral Analog-to-Digital Converter Driver + * + * Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#ifndef ADC_H_INCLUDED +#define ADC_H_INCLUDED + +/** + * \defgroup asfdoc_sam0_adc_group SAM Analog-to-Digital Converter (ADC) Driver + * + * This driver for Atmel® | SMART ARM®-based microcontrollers provides an interface for the configuration + * and management of the device's Analog-to-Digital Converter functionality, for + * the conversion of analog voltages into a corresponding digital form. + * The following driver Application Programming Interface (API) modes are covered by this manual: + * - Polled APIs + * \if ADC_CALLBACK_MODE + * - Callback APIs + * \endif + * + * The following peripheral is used by this module: + * - ADC (Analog-to-Digital Converter) + * + * The following devices can use this module: + * \if DEVICE_SAML21_SUPPORT + * - Atmel | SMART SAM L21/L22 + * - Atmel | SMART SAM C20/C21 + * - Atmel | SMART SAM R34/R35 + * \else + * - Atmel | SMART SAM D20/D21 + * - Atmel | SMART SAM R21 + * - Atmel | SMART SAM D09/D10/D11 + * - Atmel | SMART SAM DA1 + * - Atmel | SMART SAM HA1 + * \endif + * + * The outline of this documentation is as follows: + * - \ref asfdoc_sam0_adc_prerequisites + * - \ref asfdoc_sam0_adc_module_overview + * - \ref asfdoc_sam0_adc_special_considerations + * - \ref asfdoc_sam0_adc_extra_info + * - \ref asfdoc_sam0_adc_examples + * - \ref asfdoc_sam0_adc_api_overview + * + * + * \section asfdoc_sam0_adc_prerequisites Prerequisites + * + * There are no prerequisites for this module. + * + * + * \section asfdoc_sam0_adc_module_overview Module Overview + * + * This driver provides an interface for the Analog-to-Digital conversion + * functions on the device, to convert analog voltages to a corresponding + * digital value. The ADC has up to 12-bit resolution, and is capable of + * \if DEVICE_SAML21_SUPPORT + * converting up to 1,000,000 samples per second (MSPS). + * \else + * converting up to 500K samples per second (KSPS). + * \endif + * + * The ADC has a compare function for accurate monitoring of user defined + * thresholds with minimum software intervention required. + * The ADC may be configured for 8-, 10-, or 12-bit result, reducing the + * conversion time. ADC conversion results are provided left or right adjusted + * which eases calculation when the result is represented as a signed integer. + * + * The input selection is flexible, and both single-ended and differential + * measurements can be made. For differential measurements, an optional gain + * stage is available to increase the dynamic range. In addition, several + * internal signal inputs are available. The ADC can provide both signed and + * unsigned results. + * + * The ADC measurements can either be started by application software or an + * incoming event from another peripheral in the device, and both internal and + * external reference voltages can be selected. + * + * \note Internal references will be enabled by the driver, but not disabled. + * Any reference not used by the application should be disabled by the application. + * + * A simplified block diagram of the ADC can be seen in + * \ref asfdoc_sam0_adc_module_block_diagram "the figure below". + * + * \anchor asfdoc_sam0_adc_module_block_diagram + * \dot + * digraph overview { + * splines = false; + * rankdir=LR; + * + * mux1 [label="Positive input", shape=box]; + * mux2 [label="Negative input", shape=box]; + * + * + * mux3 [label="Reference", shape=box]; + * + * adc [label="ADC", shape=polygon, sides=5, orientation=90, distortion=-0.6, style=filled, fillcolor=darkolivegreen1, height=1, width=1]; + * prescaler [label="PRESCALER", shape=box, style=filled, fillcolor=lightblue]; + * + * mux1 -> adc; + * mux2 -> adc; + * mux3 -> adc:sw; + * prescaler -> adc; + * + * postproc [label="Post processing", shape=box]; + * result [label="RESULT", shape=box, style=filled, fillcolor=lightblue]; + * + * adc:e -> postproc:w; + * postproc:e -> result:w; + * + * {rank=same; mux1 mux2} + * {rank=same; prescaler adc} + * + * } + * \enddot + * + * + * \subsection asfdoc_sam0_adc_module_overview_prescaler Sample Clock Prescaler + * The ADC features a prescaler, which enables conversion at lower clock rates + * than the input Generic Clock to the ADC module. This feature can be used to + * lower the synchronization time of the digital interface to the ADC module + * via a high speed Generic Clock frequency, while still allowing the ADC + * sampling rate to be reduced. + * + * \subsection asfdoc_sam0_adc_module_overview_resolution ADC Resolution + * The ADC supports full 8-, 10-, or 12-bit resolution. Hardware + * oversampling and decimation can be used to increase the + * effective resolution at the expense of throughput. Using oversampling and + * decimation mode the ADC resolution is increased from 12-bit to an effective + * 13-, 14-, 15-, or 16-bit. In these modes the conversion rate is reduced, as + * a greater number of samples is used to achieve the increased resolution. The + * available resolutions and effective conversion rate is listed in + * \ref asfdoc_sam0_adc_module_conversion_rate "the table below". + * + * \anchor asfdoc_sam0_adc_module_conversion_rate + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Effective ADC Conversion Speed Using Oversampling
ResolutionEffective conversion rate
13-bitConversion rate divided by 4
14-bitConversion rate divided by 16
15-bitConversion rate divided by 64
16-bitConversion rate divided by 256
+ * + * \subsection asfdoc_sam0_adc_module_overview_conversion Conversion Modes + * ADC conversions can be software triggered on demand by the user application, + * if continuous sampling is not required. It is also possible to configure the + * ADC in free running mode, where new conversions are started as soon as the + * previous conversion is completed, or configure the ADC to scan across a + * number of input pins (see \ref asfdoc_sam0_adc_module_overview_pin_scan). + * + * \subsection asfdoc_sam0_adc_module_overview_diff_mode Differential and Single-ended Conversion + * The ADC has two conversion modes; differential and single-ended. When + * measuring signals where the positive input pin is always at a higher voltage + * than the negative input pin, the single-ended conversion mode should be used + * in order to achieve a full 12-bit output resolution. + * + * If however the positive input pin voltage may drop below the negative input + * pin the signed differential mode should be used. + * + * \subsection asfdoc_sam0_adc_module_overview_sample_time Sample Time + * The sample time for each ADC conversion is configurable as a number of half + * prescaled ADC clock cycles (depending on the prescaler value), allowing the + * user application to achieve faster or slower sampling depending on the + * source impedance of the ADC input channels. For applications with high + * impedance inputs the sample time can be increased to give the ADC an adequate + * time to sample and convert the input channel. + * + * The resulting sampling time is given by the following equation: + * \f[ + * t_{SAMPLE} = (sample\_length+1) \times \frac{ADC_{CLK}} {2} + * \f] + * + * \subsection asfdoc_sam0_adc_module_overview_averaging Averaging + * The ADC can be configured to trade conversion speed for accuracy by averaging + * multiple samples in hardware. This feature is suitable when operating in + * noisy conditions. + * + * You can specify any number of samples to accumulate (up to 1024) and the + * divide ratio to use (up to divide by 128). To modify these settings the + * ADC_RESOLUTION_CUSTOM needs to be set as the resolution. When this is set + * the number of samples to accumulate and the division ratio can be set by + * the configuration struct members \ref adc_config.accumulate_samples and + * \ref adc_config.divide_result. When using this mode the ADC result register + * will be set to be 16-bit wide to accommodate the larger result sizes + * produced by the accumulator. + * + * The effective ADC conversion rate will be reduced by a factor of the number + * of accumulated samples; + * however, the effective resolution will be increased according to + * \ref asfdoc_sam0_adc_module_hw_av_resolution "the table below". + * + * \anchor asfdoc_sam0_adc_module_hw_av_resolution + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Effective ADC Resolution From Various Hardware Averaging Modes
Number of samples
Final result
112-bit
213-bit
414-bit
815-bit
1616-bit
3216-bit
6416-bit
12816-bit
25616-bit
51216-bit
102416-bit
+ * + * + * \subsection asfdoc_sam0_adc_module_overview_offset_corr Offset and Gain Correction + * Inherent gain and offset errors affect the absolute accuracy of the ADC. + * + * The offset error is defined as the deviation of the ADC's actual transfer + * function from ideal straight line at zero input voltage. + * + * The gain error is defined as the deviation of the last output step's + * midpoint from the ideal straight line, after compensating for offset error. + * + * The offset correction value is subtracted from the converted data before the + * result is ready. The gain correction value is multiplied with the offset + * corrected value. + * + * The equation for both offset and gain error compensation is shown below: + * \f[ + * ADC_{RESULT} = (VALUE_{CONV} + CORR_{OFFSET}) \times CORR_{GAIN} + * \f] + * + * When enabled, a given set of offset and gain correction values can be applied + * to the sampled data in hardware, giving a corrected stream of sample data to + * the user application at the cost of an increased sample latency. + * + * In single conversion, a latency of 13 ADC Generic Clock cycles is added for + * the final sample result availability. As the correction time is always less + * than the propagation delay, in free running mode this latency appears only + * during the first conversion. After the first conversion is complete, future + * conversion results are available at the defined sampling rate. + * + * \subsection asfdoc_sam0_adc_module_overview_pin_scan Pin Scan + * In pin scan mode, the first ADC conversion will begin from the configured + * positive channel, plus the requested starting offset. When the first + * conversion is completed, the next conversion will start at the next positive + * input channel and so on, until all requested pins to scan have been sampled + * and converted. + * SAM L21/L22 has automatic sequences feature instead of pin scan mode. In automatic + * sequence mode, all of 32 positives inputs can be included in a sequence. The + * sequence starts from the lowest input, and go to the next enabled input + * automatically. + * + * Pin scanning gives a simple mechanism to sample a large number of physical + * input channel samples, using a single physical ADC channel. + * + * \subsection asfdoc_sam0_adc_module_overview_window_monitor Window Monitor + * The ADC module window monitor function can be used to automatically compare + * the conversion result against a preconfigured pair of upper and lower + * threshold values. + * + * The threshold values are evaluated differently, depending on whether + * differential or single-ended mode is selected. In differential mode, the + * upper and lower thresholds are evaluated as signed values for the comparison, + * while in single-ended mode the comparisons are made as a set of unsigned + * values. + * + * The significant bits of the lower window monitor threshold and upper window + * monitor threshold values are user-configurable, and follow the overall ADC + * sampling bit precision set when the ADC is configured by the user application. + * For example, only the eight lower bits of the window threshold values will be + * compared to the sampled data whilst the ADC is configured in 8-bit mode. + * In addition, if using differential mode, the 8th bit will be considered as + * the sign bit even if bit 9 is zero. + * + * \subsection asfdoc_sam0_adc_module_overview_events Events + * Event generation and event actions are configurable in the ADC. + * + * The ADC has two actions that can be triggered upon event reception: + * \li Start conversion + * \li Flush pipeline and start conversion + * + * The ADC can generate two events: + * \li Window monitor + * \li Result ready + * + * If the event actions are enabled in the configuration, any incoming event + * will trigger the action. + * + * If the window monitor event is enabled, an event will be generated + * when the configured window condition is detected. + * + * If the result ready event is enabled, an event will be generated when a + * conversion is completed. + * + * \note The connection of events between modules requires the use of the + * \ref asfdoc_sam0_events_group "SAM Event System Driver (EVENTS)" + * to route output event of one module to the input event of another. + * For more information on event routing, refer to the event driver + * documentation. + * + * + * \section asfdoc_sam0_adc_special_considerations Special Considerations + * + * An integrated analog temperature sensor is available for use with the ADC. + * The bandgap voltage, as well as the scaled I/O and core voltages can also be + * measured by the ADC. For internal ADC inputs, the internal source(s) may need + * to be manually enabled by the user application before they can be measured. + * + * + * \section asfdoc_sam0_adc_extra_info Extra Information + * + * For extra information, see \ref asfdoc_sam0_adc_extra. This includes: + * - \ref asfdoc_sam0_adc_extra_acronyms + * - \ref asfdoc_sam0_adc_extra_dependencies + * - \ref asfdoc_sam0_adc_extra_errata + * - \ref asfdoc_sam0_adc_extra_history + * + * + * \section asfdoc_sam0_adc_examples Examples + * + * For a list of examples related to this driver, see + * \ref asfdoc_sam0_adc_exqsg. + * + * + * \section asfdoc_sam0_adc_api_overview API Overview + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/** + * \name Module Status Flags + * + * ADC status flags, returned by \ref adc_get_status() and cleared by + * \ref adc_clear_status(). + * + * @{ + */ + +/** ADC result ready. */ +#define ADC_STATUS_RESULT_READY (1UL << 0) +/** Window monitor match. */ +#define ADC_STATUS_WINDOW (1UL << 1) +/** ADC result overwritten before read. */ +#define ADC_STATUS_OVERRUN (1UL << 2) + +/** @} */ + +#if ADC_CALLBACK_MODE == true +# if (ADC_INST_NUM > 1) +# define _ADC_INTERRUPT_VECT_NUM(n, unused) \ + SYSTEM_INTERRUPT_MODULE_ADC##n, +/** + * \internal Get the interrupt vector for the given device instance + * + * \param[in] The ADC module instance number + * + * \return Interrupt vector for of the given ADC module instance. + */ +static enum system_interrupt_vector _adc_interrupt_get_interrupt_vector( + uint32_t inst_num) +{ + static uint8_t adc_interrupt_vectors[ADC_INST_NUM] = { + MREPEAT(ADC_INST_NUM, _ADC_INTERRUPT_VECT_NUM, 0) + }; + + return (enum system_interrupt_vector)adc_interrupt_vectors[inst_num]; +} +# endif +#endif + +#if !defined(__DOXYGEN__) +uint8_t _adc_get_inst_index( + Adc *const hw); +#endif + +/** + * \name Driver Initialization and Configuration + * @{ + */ +enum status_code adc_init( + struct adc_module *const module_inst, + Adc *hw, + struct adc_config *config); + +void adc_get_config_defaults( + struct adc_config *const config); + +#if (SAMD) || (SAMHA1) || (SAMHA0) || (SAMR21) +void adc_regular_ain_channel( + uint32_t *pin_array, uint8_t size); +#endif + +/** @} */ + +/** + * \name Status Management + * @{ + */ + +/** + * \brief Retrieves the current module status. + * + * Retrieves the status of the module, giving overall state information. + * + * \param[in] module_inst Pointer to the ADC software instance struct + * + * \return Bitmask of \c ADC_STATUS_* flags. + * + * \retval ADC_STATUS_RESULT_READY ADC result is ready to be read + * \retval ADC_STATUS_WINDOW ADC has detected a value inside the set + * window range + * \retval ADC_STATUS_OVERRUN ADC result has overrun + */ +static inline uint32_t adc_get_status( + struct adc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + Adc *const adc_module = module_inst->hw; + + uint32_t int_flags = adc_module->INTFLAG.reg; + + uint32_t status_flags = 0; + + /* Check for ADC Result Ready */ + if (int_flags & ADC_INTFLAG_RESRDY) { + status_flags |= ADC_STATUS_RESULT_READY; + } + + /* Check for ADC Window Match */ + if (int_flags & ADC_INTFLAG_WINMON) { + status_flags |= ADC_STATUS_WINDOW; + } + + /* Check for ADC Overrun */ + if (int_flags & ADC_INTFLAG_OVERRUN) { + status_flags |= ADC_STATUS_OVERRUN; + } + + return status_flags; +} + +/** + * \brief Clears a module status flag. + * + * Clears the given status flag of the module. + * + * \param[in] module_inst Pointer to the ADC software instance struct + * \param[in] status_flags Bitmask of \c ADC_STATUS_* flags to clear + */ +static inline void adc_clear_status( + struct adc_module *const module_inst, + const uint32_t status_flags) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + Adc *const adc_module = module_inst->hw; + + uint32_t int_flags = 0; + + /* Check for ADC Result Ready */ + if (status_flags & ADC_STATUS_RESULT_READY) { + int_flags |= ADC_INTFLAG_RESRDY; + } + + /* Check for ADC Window Match */ + if (status_flags & ADC_STATUS_WINDOW) { + int_flags |= ADC_INTFLAG_WINMON; + } + + /* Check for ADC Overrun */ + if (status_flags & ADC_STATUS_OVERRUN) { + int_flags |= ADC_INTFLAG_OVERRUN; + } + + /* Clear interrupt flag */ + adc_module->INTFLAG.reg = int_flags; +} +/** @} */ + +/** + * \name Enable, Disable, and Reset ADC Module, Start Conversion and Read Result + * @{ + */ + +/** + * \brief Enables the ADC module. + * + * Enables an ADC module that has previously been configured. If any internal reference + * is selected it will be enabled. + * + * \param[in] module_inst Pointer to the ADC software instance struct + */ +static inline enum status_code adc_enable( + struct adc_module *const module_inst) +{ + Assert(module_inst); + Assert(module_inst->hw); + + Adc *const adc_module = module_inst->hw; + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + +#if ADC_CALLBACK_MODE == true +# if (ADC_INST_NUM > 1) + system_interrupt_enable(_adc_interrupt_get_interrupt_vector( + _adc_get_inst_index(adc_module))); +# elif (SAMC20) + system_interrupt_enable(SYSTEM_INTERRUPT_MODULE_ADC0); +# else + system_interrupt_enable(SYSTEM_INTERRUPT_MODULE_ADC); +# endif +#endif + + /* Disbale interrupt */ + adc_module->INTENCLR.reg = ADC_INTENCLR_MASK; + /* Clear interrupt flag */ + adc_module->INTFLAG.reg = ADC_INTFLAG_MASK; + + adc_module->CTRLA.reg |= ADC_CTRLA_ENABLE; + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + return STATUS_OK; +} + +/** + * \brief Disables the ADC module. + * + * Disables an ADC module that was previously enabled. + * + * \param[in] module_inst Pointer to the ADC software instance struct + */ +static inline enum status_code adc_disable( + struct adc_module *const module_inst) +{ + Assert(module_inst); + Assert(module_inst->hw); + + Adc *const adc_module = module_inst->hw; + +#if ADC_CALLBACK_MODE == true +# if (ADC_INST_NUM > 1) + system_interrupt_disable(_adc_interrupt_get_interrupt_vector( + _adc_get_inst_index(adc_module))); +# elif (SAMC20) + system_interrupt_disable(SYSTEM_INTERRUPT_MODULE_ADC0); +# else + system_interrupt_disable(SYSTEM_INTERRUPT_MODULE_ADC); +# endif +#endif + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + + /* Disbale interrupt */ + adc_module->INTENCLR.reg = ADC_INTENCLR_MASK; + /* Clear interrupt flag */ + adc_module->INTFLAG.reg = ADC_INTFLAG_MASK; + + adc_module->CTRLA.reg &= ~ADC_CTRLA_ENABLE; + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + return STATUS_OK; +} + +/** + * \brief Resets the ADC module. + * + * Resets an ADC module, clearing all module state, and registers to their + * default values. + * + * \param[in] module_inst Pointer to the ADC software instance struct + */ +static inline enum status_code adc_reset( + struct adc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + Adc *const adc_module = module_inst->hw; + + /* Disable to make sure the pipeline is flushed before reset */ + adc_disable(module_inst); + + /* Software reset the module */ + adc_module->CTRLA.reg |= ADC_CTRLA_SWRST; + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + return STATUS_OK; +} + + +/** + * \brief Enables an ADC event input or output. + * + * Enables one or more input or output events to or from the ADC module. See + * \ref adc_events "Struct adc_events" for a list of events this module supports. + * + * \note Events cannot be altered while the module is enabled. + * + * \param[in] module_inst Software instance for the ADC peripheral + * \param[in] events Struct containing flags of events to enable + */ +static inline void adc_enable_events( + struct adc_module *const module_inst, + struct adc_events *const events) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + Assert(events); + + Adc *const adc_module = module_inst->hw; + + uint32_t event_mask = 0; + + /* Configure Window Monitor event */ + if (events->generate_event_on_window_monitor) { + event_mask |= ADC_EVCTRL_WINMONEO; + } + + /* Configure Result Ready event */ + if (events->generate_event_on_conversion_done) { + event_mask |= ADC_EVCTRL_RESRDYEO; + } + + adc_module->EVCTRL.reg |= event_mask; +} + +/** + * \brief Disables an ADC event input or output. + * + * Disables one or more input or output events to or from the ADC module. See + * \ref adc_events "Struct adc_events" for a list of events this module supports. + * + * \note Events cannot be altered while the module is enabled. + * + * \param[in] module_inst Software instance for the ADC peripheral + * \param[in] events Struct containing flags of events to disable + */ +static inline void adc_disable_events( + struct adc_module *const module_inst, + struct adc_events *const events) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + Assert(events); + + Adc *const adc_module = module_inst->hw; + + uint32_t event_mask = 0; + + /* Configure Window Monitor event */ + if (events->generate_event_on_window_monitor) { + event_mask |= ADC_EVCTRL_WINMONEO; + } + + /* Configure Result Ready event */ + if (events->generate_event_on_conversion_done) { + event_mask |= ADC_EVCTRL_RESRDYEO; + } + + adc_module->EVCTRL.reg &= ~event_mask; +} + +/** + * \brief Starts an ADC conversion. + * + * Starts a new ADC conversion. + * + * \param[in] module_inst Pointer to the ADC software instance struct + */ +static inline void adc_start_conversion( + struct adc_module *const module_inst) +{ + Assert(module_inst); + Assert(module_inst->hw); + + Adc *const adc_module = module_inst->hw; + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + + adc_module->SWTRIG.reg |= ADC_SWTRIG_START; + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } +} + +/** + * \brief Reads the ADC result. + * + * Reads the result from an ADC conversion that was previously started. + * + * \param[in] module_inst Pointer to the ADC software instance struct + * \param[out] result Pointer to store the result value in + * + * \return Status of the ADC read request. + * \retval STATUS_OK The result was retrieved successfully + * \retval STATUS_BUSY A conversion result was not ready + * \retval STATUS_ERR_OVERFLOW The result register has been overwritten by the + * ADC module before the result was read by the software + */ +static inline enum status_code adc_read( + struct adc_module *const module_inst, + uint16_t *result) +{ + Assert(module_inst); + Assert(module_inst->hw); + Assert(result); + + if (!(adc_get_status(module_inst) & ADC_STATUS_RESULT_READY)) { + /* Result not ready */ + return STATUS_BUSY; + } + + Adc *const adc_module = module_inst->hw; + +#if (SAMD) || (SAMHA1) || (SAMHA0) || (SAMR21) + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } +#endif + + /* Get ADC result */ + *result = adc_module->RESULT.reg; + + /* Reset ready flag */ + adc_clear_status(module_inst, ADC_STATUS_RESULT_READY); + + if (adc_get_status(module_inst) & ADC_STATUS_OVERRUN) { + adc_clear_status(module_inst, ADC_STATUS_OVERRUN); + return STATUS_ERR_OVERFLOW; + } + + return STATUS_OK; +} + +/** @} */ + +/** + * \name Runtime Changes of ADC Module + * @{ + */ + +/** + * \brief Flushes the ADC pipeline. + * + * Flushes the pipeline and restarts the ADC clock on the next peripheral clock + * edge. All conversions in progress will be lost. When flush is complete, the + * module will resume where it left off. + * + * \param[in] module_inst Pointer to the ADC software instance struct + */ +static inline void adc_flush( + struct adc_module *const module_inst) +{ + Assert(module_inst); + Assert(module_inst->hw); + + Adc *const adc_module = module_inst->hw; + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + + adc_module->SWTRIG.reg |= ADC_SWTRIG_FLUSH; + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } +} +void adc_set_window_mode( + struct adc_module *const module_inst, + const enum adc_window_mode window_mode, + const int16_t window_lower_value, + const int16_t window_upper_value); + +/** + * \brief Sets positive ADC input pin. + * + * Sets the positive ADC input pin selection. + * + * \param[in] module_inst Pointer to the ADC software instance struct + * \param[in] positive_input Positive input pin + */ +static inline void adc_set_positive_input( + struct adc_module *const module_inst, + const enum adc_positive_input positive_input) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + Adc *const adc_module = module_inst->hw; + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + + /* Set positive input pin */ + adc_module->INPUTCTRL.reg = + (adc_module->INPUTCTRL.reg & ~ADC_INPUTCTRL_MUXPOS_Msk) | + (positive_input); + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } +} + + +/** + * \brief Sets negative ADC input pin for differential mode. + * + * Sets the negative ADC input pin, when the ADC is configured in differential + * mode. + * + * \param[in] module_inst Pointer to the ADC software instance struct + * \param[in] negative_input Negative input pin + */ +static inline void adc_set_negative_input( + struct adc_module *const module_inst, + const enum adc_negative_input negative_input) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + Adc *const adc_module = module_inst->hw; + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + + /* Set negative input pin */ + adc_module->INPUTCTRL.reg = + (adc_module->INPUTCTRL.reg & ~ADC_INPUTCTRL_MUXNEG_Msk) | + (negative_input); + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } +} + +/** @} */ + +#if ADC_CALLBACK_MODE == true +/** + * \name Enable and Disable Interrupts + * @{ + */ + +/** + * \brief Enable interrupt. + * + * Enable the given interrupt request from the ADC module. + * + * \param[in] module_inst Pointer to the ADC software instance struct + * \param[in] interrupt Interrupt to enable + */ +static inline void adc_enable_interrupt(struct adc_module *const module_inst, + enum adc_interrupt_flag interrupt) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + Adc *const adc_module = module_inst->hw; + /* Enable interrupt */ + adc_module->INTENSET.reg = interrupt; +} + +/** + * \brief Disable interrupt. + * + * Disable the given interrupt request from the ADC module. + * + * \param[in] module_inst Pointer to the ADC software instance struct + * \param[in] interrupt Interrupt to disable + */ +static inline void adc_disable_interrupt(struct adc_module *const module_inst, + enum adc_interrupt_flag interrupt) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + Adc *const adc_module = module_inst->hw; + /* Enable interrupt */ + adc_module->INTENCLR.reg = interrupt; +} + +/** @} */ +#endif /* ADC_CALLBACK_MODE == true */ + +#ifdef __cplusplus +} +#endif + +/** @} */ + + +/** + * \page asfdoc_sam0_adc_extra Extra Information for ADC Driver + * + * \section asfdoc_sam0_adc_extra_acronyms Acronyms + * Below is a table listing the acronyms used in this module, along with their + * intended meanings. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
AcronymDescription
ADCAnalog-to-Digital Converter
DACDigital-to-Analog Converter
LSBLeast Significant Bit
MSBMost Significant Bit
DMADirect Memory Access
+ * + * + * \section asfdoc_sam0_adc_extra_dependencies Dependencies + * This driver has the following dependencies: + * + * - \ref asfdoc_sam0_system_pinmux_group "System Pin Multiplexer Driver" + * + * + * \section asfdoc_sam0_adc_extra_errata Errata + * There are no errata related to this driver. + * + * + * \section asfdoc_sam0_adc_extra_history Module History + * An overview of the module history is presented in the table below, with + * details on the enhancements and fixes made to the module since its first + * release. The current version of this corresponds to the newest version in + * the table. + * + * + * + * + * + * \if DEVICE_SAML21_SUPPORT + * + * + * + * \else + * + * + * + * + * + * + * + * + * + * + * + * + * \endif + *
Changelog
Initial Release
Added support for SAM R21
Added support for SAM D21 and new DMA quick start guide
Added ADC calibration constant loading from the device signature + * row when the module is initialized
Initial Release
+ */ + +/** + * \page asfdoc_sam0_adc_exqsg Examples for ADC Driver + * + * This is a list of the available Quick Start guides (QSGs) and example + * applications for \ref asfdoc_sam0_adc_group. QSGs are simple examples with + * step-by-step instructions to configure and use this driver in a selection of + * use cases. Note that a QSG can be compiled as a standalone application or be + * added to the user application. + * + * - \subpage asfdoc_sam0_adc_basic_use_case + * \if ADC_CALLBACK_MODE + * - \subpage asfdoc_sam0_adc_basic_use_case_callback + * \endif + * - \subpage asfdoc_sam0_adc_dma_use_case + * + * \page asfdoc_sam0_adc_document_revision_history Document Revision History + * + * + * + * + * + * + * + * \if DEVICE_SAML21_SUPPORT + * + * + * + * + * + * + * + * + * + * + * \else + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * \endif + *
Doc. Rev.DateComments
42451B12/2015Added support for SAM L22
42451A07/2015Initial document release
42109E12/2015Added support for SAM DA1 and SAM D09
42109D12/2014Added support for SAM R21 and SAM D10/D11
42109C01/2014Added support for SAM D21
42109B06/2013Added additional documentation on the event system. Corrected + * documentation typos.
42109A06/2013Initial release
+ */ + +#endif /* ADC_H_INCLUDED */ diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/adc/adc_callback.h b/src/boards/mcu/samr34/ASF/sam0/drivers/adc/adc_callback.h new file mode 100644 index 000000000..f64369081 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/adc/adc_callback.h @@ -0,0 +1,172 @@ +/** + * \file + * + * \brief SAM Peripheral Analog-to-Digital Converter Driver + * + * Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#ifndef ADC_CALLBACK_H_INCLUDED +#define ADC_CALLBACK_H_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup asfdoc_sam0_adc_group + * + * @{ + */ + +#include + +/** + * Enum for the possible types of ADC asynchronous jobs that may be issued to + * the driver. + */ +enum adc_job_type { + /** Asynchronous ADC read into a user provided buffer */ + ADC_JOB_READ_BUFFER, +}; + +/** + * \name Callback Management + * @{ + */ +void adc_register_callback( + struct adc_module *const module, + adc_callback_t callback_func, + enum adc_callback callback_type); + +void adc_unregister_callback( + struct adc_module *module, + enum adc_callback callback_type); + +/** + * \brief Enables callback. + * + * Enables the callback function registered by \ref + * adc_register_callback. The callback function will be called from the + * interrupt handler when the conditions for the callback type are met. + * + * \param[in] module Pointer to ADC software instance struct + * \param[in] callback_type Callback type given by an enum + * + * \return Status of the operation. + * \retval STATUS_OK If operation was completed + * \retval STATUS_ERR_INVALID If operation was not completed, + * due to invalid callback_type + * + */ +static inline void adc_enable_callback( + struct adc_module *const module, + enum adc_callback callback_type) +{ + /* Sanity check arguments */ + Assert(module); + + /* Enable callback */ + module->enabled_callback_mask |= (1 << callback_type); + + /* Enable window interrupt if this is a window callback */ + if (callback_type == ADC_CALLBACK_WINDOW) { + adc_enable_interrupt(module, ADC_INTERRUPT_WINDOW); + } + /* Enable overrun interrupt if error callback is registered */ + if (callback_type == ADC_CALLBACK_ERROR) { + adc_enable_interrupt(module, ADC_INTERRUPT_OVERRUN); + } +} + +/** + * \brief Disables callback. + * + * Disables the callback function registered by the \ref + * adc_register_callback. + * + * \param[in] module Pointer to ADC software instance struct + * \param[in] callback_type Callback type given by an enum + * + * \return Status of the operation. + * \retval STATUS_OK If operation was completed + * \retval STATUS_ERR_INVALID If operation was not completed, + * due to invalid callback_type + * + */ +static inline void adc_disable_callback( + struct adc_module *const module, + enum adc_callback callback_type) +{ + /* Sanity check arguments */ + Assert(module); + + /* Disable callback */ + module->enabled_callback_mask &= ~(1 << callback_type); + + /* Disable window interrupt if this is a window callback */ + if (callback_type == ADC_CALLBACK_WINDOW) { + adc_disable_interrupt(module, ADC_INTERRUPT_WINDOW); + } + /* Disable overrun interrupt if this is the error callback */ + if (callback_type == ADC_CALLBACK_ERROR) { + adc_disable_interrupt(module, ADC_INTERRUPT_OVERRUN); + } +} + +/** @} */ + + +/** + * \name Job Management + * @{ + */ +enum status_code adc_read_buffer_job( + struct adc_module *const module_inst, + uint16_t *buffer, + uint16_t samples); + +enum status_code adc_get_job_status( + struct adc_module *module_inst, + enum adc_job_type type); + +void adc_abort_job( + struct adc_module *module_inst, + enum adc_job_type type); +/** @} */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ADC_CALLBACK_H_INCLUDED */ diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/adc/adc_sam_l_c/adc.c b/src/boards/mcu/samr34/ASF/sam0/drivers/adc/adc_sam_l_c/adc.c new file mode 100644 index 000000000..ebf20eca8 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/adc/adc_sam_l_c/adc.c @@ -0,0 +1,830 @@ +/** + * \file + * + * \brief SAM Peripheral Analog-to-Digital Converter Driver + * + * Copyright (c) 2014-2020 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#include "adc.h" +#if (ADC_INST_NUM > 1) || (SAMC20) + +# define _ADC_GCLK_ID(n,unused) TPASTE3(ADC,n,_GCLK_ID), +# define _ADC_APBCMASK(n,unused) TPASTE2(MCLK_APBCMASK_ADC,n), + +# define _ADC_FUSES_BIASCOMP_ADDR(n,unused) TPASTE3(ADC,n,_FUSES_BIASCOMP_ADDR), +# define _ADC_FUSES_BIASCOMP_Pos(n,unused) TPASTE3(ADC,n,_FUSES_BIASCOMP_Pos), +# define _ADC_FUSES_BIASREFBUF_ADDR(n,unused) TPASTE3(ADC,n,_FUSES_BIASREFBUF_ADDR), +# define _ADC_FUSES_BIASREFBUF_Pos(n,unused) TPASTE3(ADC,n,_FUSES_BIASREFBUF_Pos), +# define _ADC_EXTCHANNEL_MSB(n,unused) TPASTE3(ADC,n,_EXTCHANNEL_MSB), + +# define ADC_GCLK_ID MREPEAT(ADC_INST_NUM, _ADC_GCLK_ID, 0) +# define ADC_APBCMASKS MREPEAT(ADC_INST_NUM, _ADC_APBCMASK, 0) + +# define ADC_FUSES_BIASCOMP_ADDR MREPEAT(ADC_INST_NUM, _ADC_FUSES_BIASCOMP_ADDR, 0) +# define ADC_FUSES_BIASCOMP_Pos MREPEAT(ADC_INST_NUM, _ADC_FUSES_BIASCOMP_Pos, 0) +# define ADC_FUSES_BIASREFBUF_ADDR MREPEAT(ADC_INST_NUM, _ADC_FUSES_BIASREFBUF_ADDR, 0) +# define ADC_FUSES_BIASREFBUF_Pos MREPEAT(ADC_INST_NUM, _ADC_FUSES_BIASREFBUF_Pos, 0) +# define ADC_EXTCHANNEL_MSB MREPEAT(ADC_INST_NUM, _ADC_EXTCHANNEL_MSB, 0) + +#endif + +/* List of ADC GCLK IDs */ +const uint8_t _adc_gclk_ids[ADC_INST_NUM] = { ADC_GCLK_ID }; + +/* List of ADC APB Masks */ +#if (ADC_INST_NUM > 1) || (SAMC20) +const uint32_t _adc_apbcmasks[ADC_INST_NUM] = { ADC_APBCMASKS }; +#endif + +/* List of Number of external channels of ADC modules. */ +const uint32_t _adc_extchannel_msb[ADC_INST_NUM] = { ADC_EXTCHANNEL_MSB }; + +/* List of address of comparator scaling of ADC modules. */ +const uint32_t _adc_biascomp_addr[ADC_INST_NUM] = { ADC_FUSES_BIASCOMP_ADDR }; + +/* List of address of bias reference buffer scaling of ADC modules. */ +const uint32_t _adc_biasrefbuf_addr[ADC_INST_NUM] = { ADC_FUSES_BIASREFBUF_ADDR }; + +/* List of offset of comparator scaling of ADC modules. */ +const uint8_t _adc_biascomp_pos[ADC_INST_NUM] = { ADC_FUSES_BIASCOMP_Pos }; + +/* List of offset of bias reference buffer scaling of ADC modules. */ +const uint8_t _adc_biasrefbuf_pos[ADC_INST_NUM] = { ADC_FUSES_BIASREFBUF_Pos }; + + +/** + * \internal Find the index of given ADC module instance. + * + * \param[in] ADC module instance pointer. + * + * \return Index of the given ADC module instance. + */ +uint8_t _adc_get_inst_index( + Adc *const hw) +{ + /* List of available ADC modules. */ + Adc *const adc_modules[ADC_INST_NUM] = ADC_INSTS; + + /* Find index for ADC instance. */ + for (uint32_t i = 0; i < ADC_INST_NUM; i++) { + if (hw == adc_modules[i]) { + return i; + } + } + + /* Invalid data given. */ + Assert(false); + return 0; +} + +/** + * \brief Initializes an ADC configuration structure to defaults. + * + * Initializes a given ADC configuration struct to a set of known default + * values. This function should be called on any new instance of the + * configuration struct before being modified by the user application. + * + * The default configuration is as follows: + * \li GCLK generator 0 (GCLK main) clock source + * \li Internal bandgap reference + * \li Div 2 clock prescaler + * \li 12-bit resolution + * \li Window monitor disabled + * \li Positive input on ADC PIN 1 + * \li Negative input on Internal ground + * \li Averaging disabled + * \li Oversampling disabled + * \li Right adjust data + * \li Single-ended mode + * \li Free running disabled + * \li All events (input and generation) disabled + * \li ADC run in standby disabled + * \li ADC On demand disabled + * \li No sampling time compensation + * \li Disable the positive input sequense + * \li No reference compensation + * \li No gain/offset correction + * \li No added sampling time + * + * \param[out] config Pointer to configuration struct to initialize to + * default values + */ +void adc_get_config_defaults(struct adc_config *const config) +{ + Assert(config); + config->clock_source = GCLK_GENERATOR_0; + config->reference = ADC_REFERENCE_INTREF; + config->clock_prescaler = ADC_CLOCK_PRESCALER_DIV2; + config->resolution = ADC_RESOLUTION_12BIT; + config->window.window_mode = ADC_WINDOW_MODE_DISABLE; + config->window.window_upper_value = 0; + config->window.window_lower_value = 0; +#if SAMR30 || SAMR34 || SAMR35 || (WLR089) + config->positive_input = ADC_POSITIVE_INPUT_PIN6; +#else + config->positive_input = ADC_POSITIVE_INPUT_PIN1; +#endif + config->negative_input = ADC_NEGATIVE_INPUT_GND; + config->accumulate_samples = ADC_ACCUMULATE_DISABLE; + config->divide_result = ADC_DIVIDE_RESULT_DISABLE; + config->left_adjust = false; + config->differential_mode = false; + config->freerunning = false; + config->event_action = ADC_EVENT_ACTION_DISABLED; + config->run_in_standby = false; + config->on_demand = false; + config->sampling_time_compensation_enable = false; + config->positive_input_sequence_mask_enable = 0; + config->reference_compensation_enable = false; + config->correction.correction_enable = false; + config->correction.gain_correction = ADC_GAINCORR_RESETVALUE; + config->correction.offset_correction = ADC_OFFSETCORR_RESETVALUE; + config->sample_length = 0; +} + +/** + * \brief Sets the ADC window mode. + * + * Sets the ADC window mode to a given mode and value range. + * + * \param[in] module_inst Pointer to the ADC software instance struct + * \param[in] window_mode Window monitor mode to set + * \param[in] window_lower_value Lower window monitor threshold value + * \param[in] window_upper_value Upper window monitor threshold value + */ +void adc_set_window_mode( + struct adc_module *const module_inst, + const enum adc_window_mode window_mode, + const int16_t window_lower_value, + const int16_t window_upper_value) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + Adc *const adc_module = module_inst->hw; + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + + /* Set window mode */ + uint32_t ctrlc = adc_module->CTRLC.reg; + ctrlc = (ctrlc & (~ADC_CTRLC_WINMODE_Msk)) | window_mode; + adc_module->CTRLC.reg = ctrlc; + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + + /* Set lower window monitor threshold value */ + adc_module->WINLT.reg = window_lower_value; + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + + /* Set upper window monitor threshold value */ + adc_module->WINUT.reg = window_upper_value; + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } +} + +/** +* \internal Configure MUX settings for the analog pins. +* +* This function will set the given ADC input pins +* to the analog function in the pin mux, giving +* the ADC access to the analog signal. +* +* \param [in] index Index of the ADC module instance. +* \param [in] pin AINxx pin to configure +*/ +static inline void _adc_configure_ain_pin(uint8_t index, uint32_t pin) +{ +#define PIN_INVALID_ADC_AIN 0xFFFFUL + + /* Pinmapping table for AINxx -> GPIO pin number */ +#if (SAML21) || (SAML22) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + const uint32_t pinmapping[] = { +#if (SAML21E) + PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_PA04B_ADC_AIN4, PIN_PA05B_ADC_AIN5, + PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_PA08B_ADC_AIN16, PIN_PA09B_ADC_AIN17, + PIN_PA10B_ADC_AIN18, PIN_PA11B_ADC_AIN19, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, +#elif (SAMR30E) + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_PA06B_ADC_AIN6, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, +#elif (SAML21G) || (SAMR30G) || (SAMR34J) || (SAMR35J) || (WLR089U0) +#if !(SAMR30 || SAMR34 || SAMR35 || (WLR089)) + PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1, +#endif +#if (SAMR34JXXB) || (SAMR35JXXB) || (WLR089U0) + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, +#else + PIN_PB08B_ADC_AIN2, PIN_PB09B_ADC_AIN3, +#endif + PIN_PA04B_ADC_AIN4, PIN_PA05B_ADC_AIN5, + PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7, +#if (SAMR34JXXB) || (SAMR35JXXB) || (WLR089U0) + PIN_PB00B_ADC_AIN8, PIN_INVALID_ADC_AIN, +#else + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, +#endif + PIN_PB02B_ADC_AIN10, PIN_PB03B_ADC_AIN11, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_PA08B_ADC_AIN16, PIN_PA09B_ADC_AIN17, + PIN_PA10B_ADC_AIN18, PIN_PA11B_ADC_AIN19, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, +#elif (SAML21J) + PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1, + PIN_PB08B_ADC_AIN2, PIN_PB09B_ADC_AIN3, + PIN_PA04B_ADC_AIN4, PIN_PA05B_ADC_AIN5, + PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7, + PIN_PB00B_ADC_AIN8, PIN_PB01B_ADC_AIN9, + PIN_PB02B_ADC_AIN10, PIN_PB03B_ADC_AIN11, + PIN_PB04B_ADC_AIN12, PIN_PB05B_ADC_AIN13, + PIN_PB06B_ADC_AIN14, PIN_PB07B_ADC_AIN15, + PIN_PA08B_ADC_AIN16, PIN_PA09B_ADC_AIN17, + PIN_PA10B_ADC_AIN18, PIN_PA11B_ADC_AIN19, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, +#elif (SAML22G) + PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1, + PIN_PB08B_ADC_AIN2, PIN_PB09B_ADC_AIN3, + PIN_PA04B_ADC_AIN4, PIN_PA05B_ADC_AIN5, + PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_PB02B_ADC_AIN10, PIN_PB03B_ADC_AIN11, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, +#elif (SAML22J) + PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1, + PIN_PB08B_ADC_AIN2, PIN_PB09B_ADC_AIN3, + PIN_PA04B_ADC_AIN4, PIN_PA05B_ADC_AIN5, + PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7, + PIN_PB00B_ADC_AIN8, PIN_PB01B_ADC_AIN9, + PIN_PB02B_ADC_AIN10, PIN_PB03B_ADC_AIN11, + PIN_PB04B_ADC_AIN12, PIN_PB05B_ADC_AIN13, + PIN_PB06B_ADC_AIN14, PIN_PB07B_ADC_AIN15, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, +#elif (SAML22N) + PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1, + PIN_PB08B_ADC_AIN2, PIN_PB09B_ADC_AIN3, + PIN_PA04B_ADC_AIN4, PIN_PA05B_ADC_AIN5, + PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7, + PIN_PB00B_ADC_AIN8, PIN_PB01B_ADC_AIN9, + PIN_PB02B_ADC_AIN10, PIN_PB03B_ADC_AIN11, + PIN_PB04B_ADC_AIN12, PIN_PB05B_ADC_AIN13, + PIN_PB06B_ADC_AIN14, PIN_PB07B_ADC_AIN15, + PIN_PC00B_ADC_AIN16, PIN_PC01B_ADC_AIN17, + PIN_PC02B_ADC_AIN18, PIN_PC03B_ADC_AIN19, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, +# else +# error ADC pin mappings are not defined for this device. +# endif + }; +#elif (SAMC20) + const uint32_t pinmapping[] = { +# if (SAMC20E) + PIN_PA02B_ADC0_AIN0, PIN_PA03B_ADC0_AIN1, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_PA04B_ADC0_AIN4, PIN_PA05B_ADC0_AIN5, + PIN_PA06B_ADC0_AIN6, PIN_PA07B_ADC0_AIN7, + PIN_PA08B_ADC0_AIN8, PIN_PA09B_ADC0_AIN9, + PIN_PA10B_ADC0_AIN10, PIN_PA11B_ADC0_AIN11, +# elif (SAMC20G) + PIN_PA02B_ADC0_AIN0, PIN_PA03B_ADC0_AIN1, + PIN_PB08B_ADC0_AIN2, PIN_PB09B_ADC0_AIN3, + PIN_PA04B_ADC0_AIN4, PIN_PA05B_ADC0_AIN5, + PIN_PA06B_ADC0_AIN6, PIN_PA07B_ADC0_AIN7, + PIN_PA08B_ADC0_AIN8, PIN_PA09B_ADC0_AIN9, + PIN_PA10B_ADC0_AIN10, PIN_PA11B_ADC0_AIN11, +# elif (SAMC20J) + PIN_PA02B_ADC0_AIN0, PIN_PA03B_ADC0_AIN1, + PIN_PB08B_ADC0_AIN2, PIN_PB09B_ADC0_AIN3, + PIN_PA04B_ADC0_AIN4, PIN_PA05B_ADC0_AIN5, + PIN_PA06B_ADC0_AIN6, PIN_PA07B_ADC0_AIN7, + PIN_PA08B_ADC0_AIN8, PIN_PA09B_ADC0_AIN9, + PIN_PA10B_ADC0_AIN10, PIN_PA11B_ADC0_AIN11, +# else +# error ADC pin mappings are not defined for this device. +# endif + }; +#elif (SAMC21) + const uint32_t *pinmapping = NULL;; + const uint32_t pinmapping0[] = { +# if (SAMC21E) + PIN_PA02B_ADC0_AIN0, PIN_PA03B_ADC0_AIN1, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_PA04B_ADC0_AIN4, PIN_PA05B_ADC0_AIN5, + PIN_PA06B_ADC0_AIN6, PIN_PA07B_ADC0_AIN7, + PIN_PA08B_ADC0_AIN8, PIN_PA09B_ADC0_AIN9, + PIN_PA10B_ADC0_AIN10, PIN_PA11B_ADC0_AIN11, +# elif (SAMC21G) + PIN_PA02B_ADC0_AIN0, PIN_PA03B_ADC0_AIN1, + PIN_PB08B_ADC0_AIN2, PIN_PB09B_ADC0_AIN3, + PIN_PA04B_ADC0_AIN4, PIN_PA05B_ADC0_AIN5, + PIN_PA06B_ADC0_AIN6, PIN_PA07B_ADC0_AIN7, + PIN_PA08B_ADC0_AIN8, PIN_PA09B_ADC0_AIN9, + PIN_PA10B_ADC0_AIN10, PIN_PA11B_ADC0_AIN11, +# elif (SAMC21J) + PIN_PA02B_ADC0_AIN0, PIN_PA03B_ADC0_AIN1, + PIN_PB08B_ADC0_AIN2, PIN_PB09B_ADC0_AIN3, + PIN_PA04B_ADC0_AIN4, PIN_PA05B_ADC0_AIN5, + PIN_PA06B_ADC0_AIN6, PIN_PA07B_ADC0_AIN7, + PIN_PA08B_ADC0_AIN8, PIN_PA09B_ADC0_AIN9, + PIN_PA10B_ADC0_AIN10, PIN_PA11B_ADC0_AIN11, +# else +# error ADC pin mappings are not defined for this device. +# endif + }; + const uint32_t pinmapping1[] = { +# if (SAMC21E) + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_PA08B_ADC1_AIN10, PIN_PA09B_ADC1_AIN11, +# elif (SAMC21G) + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_PB02B_ADC1_AIN2, PIN_PB03B_ADC1_AIN3, + PIN_PB08B_ADC1_AIN4, PIN_PB09B_ADC1_AIN5, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_PA08B_ADC1_AIN10, PIN_PA09B_ADC1_AIN11, +# elif (SAMC21J) + PIN_PB00B_ADC1_AIN0, PIN_PB01B_ADC1_AIN1, + PIN_PB02B_ADC1_AIN2, PIN_PB03B_ADC1_AIN3, + PIN_PB08B_ADC1_AIN4, PIN_PB09B_ADC1_AIN5, + PIN_PB04B_ADC1_AIN6, PIN_PB05B_ADC1_AIN7, + PIN_PB06B_ADC1_AIN8, PIN_PB07B_ADC1_AIN9, + PIN_PA08B_ADC1_AIN10, PIN_PA09B_ADC1_AIN11, +# else +# error ADC pin mappings are not defined for this device. +# endif + }; + + switch(index) { + case 0: + pinmapping = pinmapping0; + break; + case 1: + pinmapping = pinmapping1; + break; + default: + break; + } + Assert(pinmapping); +#endif + + uint32_t pin_map_result = PIN_INVALID_ADC_AIN; + + if (pin <= _adc_extchannel_msb[index]) { + pin_map_result = pinmapping[pin >> ADC_INPUTCTRL_MUXPOS_Pos]; + + Assert(pin_map_result != PIN_INVALID_ADC_AIN); + + struct system_pinmux_config config; + system_pinmux_get_config_defaults(&config); + + /* Analog functions are all on MUX setting B */ + config.input_pull = SYSTEM_PINMUX_PIN_PULL_NONE; + config.mux_position = 1; + + system_pinmux_pin_set_config(pin_map_result, &config); + } +} + +/** + * \internal Writes an ADC configuration to the hardware module. + * + * Writes out a given ADC module configuration to the hardware module. + * + * \param[in] index Index of the ADC module instance + * \param[out] module_inst Pointer to the ADC software instance struct + * \param[in] config Pointer to configuration struct + * + * \return Status of the configuration procedure. + * \retval STATUS_OK The configuration was successful + * \retval STATUS_ERR_INVALID_ARG Invalid argument(s) were provided + */ +static enum status_code _adc_set_config( + uint8_t index, + struct adc_module *const module_inst, + struct adc_config *const config) +{ + uint8_t adjres = 0; + uint32_t resolution = ADC_RESOLUTION_16BIT; + enum adc_accumulate_samples accumulate = ADC_ACCUMULATE_DISABLE; + + /* Get the hardware module pointer */ + Adc *const adc_module = module_inst->hw; + + /* Configure GCLK channel and enable clock */ + struct system_gclk_chan_config gclk_chan_conf; + system_gclk_chan_get_config_defaults(&gclk_chan_conf); + gclk_chan_conf.source_generator = config->clock_source; + system_gclk_chan_set_config(_adc_gclk_ids[index], &gclk_chan_conf); + system_gclk_chan_enable(_adc_gclk_ids[index]); + + /* Setup pinmuxing for analog inputs */ + _adc_configure_ain_pin(index, config->positive_input); + _adc_configure_ain_pin(index, config->negative_input); + + /* Set pinmux for positive input sequence*/ + for(uint8_t i=0;i <= _adc_extchannel_msb[index];i++){ + if(config->positive_input_sequence_mask_enable & (1 << i)){ + _adc_configure_ain_pin(index, i); + } + } + + /* Configure run in standby and on demand */ + adc_module->CTRLA.reg = ((config->run_in_standby << ADC_CTRLA_RUNSTDBY_Pos) + | (config->on_demand << ADC_CTRLA_ONDEMAND_Pos)) ; + + /* Configure reference */ + adc_module->REFCTRL.reg = + (config->reference_compensation_enable << ADC_REFCTRL_REFCOMP_Pos) + | (config->reference); + + /* Set adjusting result and number of samples */ + switch (config->resolution) { + + case ADC_RESOLUTION_CUSTOM: + adjres = config->divide_result; + accumulate = config->accumulate_samples; + /* 16-bit result register */ + resolution = ADC_RESOLUTION_16BIT; + break; + + case ADC_RESOLUTION_13BIT: + /* Increase resolution by 1 bit */ + adjres = ADC_DIVIDE_RESULT_2; + accumulate = ADC_ACCUMULATE_SAMPLES_4; + /* 16-bit result register */ + resolution = ADC_RESOLUTION_16BIT; + break; + + case ADC_RESOLUTION_14BIT: + /* Increase resolution by 2 bit */ + adjres = ADC_DIVIDE_RESULT_4; + accumulate = ADC_ACCUMULATE_SAMPLES_16; + /* 16-bit result register */ + resolution = ADC_RESOLUTION_16BIT; + break; + case ADC_RESOLUTION_15BIT: + /* Increase resolution by 3 bit */ + adjres = ADC_DIVIDE_RESULT_2; + accumulate = ADC_ACCUMULATE_SAMPLES_64; + /* 16-bit result register */ + resolution = ADC_RESOLUTION_16BIT; + break; + + case ADC_RESOLUTION_16BIT: + /* Increase resolution by 4 bit */ + adjres = ADC_DIVIDE_RESULT_DISABLE; + accumulate = ADC_ACCUMULATE_SAMPLES_256; + /* 16-bit result register */ + resolution = ADC_RESOLUTION_16BIT; + break; + case ADC_RESOLUTION_8BIT: + /* 8-bit result register */ + resolution = ADC_RESOLUTION_8BIT; + break; + case ADC_RESOLUTION_10BIT: + /* 10-bit result register */ + resolution = ADC_RESOLUTION_10BIT; + break; + case ADC_RESOLUTION_12BIT: + /* 12-bit result register */ + resolution = ADC_RESOLUTION_12BIT; + break; + + default: + /* Unknown. Abort. */ + return STATUS_ERR_INVALID_ARG; + } + + adc_module->AVGCTRL.reg = ADC_AVGCTRL_ADJRES(adjres) | accumulate; + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + + /* Check validity of sample length value */ + if (config->sample_length > 63) { + return STATUS_ERR_INVALID_ARG; + } else { + /* Configure sample length */ + adc_module->SAMPCTRL.reg = + (config->sample_length << ADC_SAMPCTRL_SAMPLEN_Pos) + | (config->sampling_time_compensation_enable << ADC_SAMPCTRL_OFFCOMP_Pos); + } + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + + /* Configure CTRLB */ + adc_module->CTRLB.reg = + config->clock_prescaler; + adc_module->CTRLC.reg = + resolution | + (config->correction.correction_enable << ADC_CTRLC_CORREN_Pos) | + (config->freerunning << ADC_CTRLC_FREERUN_Pos) | + (config->left_adjust << ADC_CTRLC_LEFTADJ_Pos) | + (config->differential_mode << ADC_CTRLC_DIFFMODE_Pos); + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + + /* Check validity of window thresholds */ + if (config->window.window_mode != ADC_WINDOW_MODE_DISABLE) { + switch (resolution) { + case ADC_RESOLUTION_8BIT: + if (config->differential_mode && + (config->window.window_lower_value > 127 || + config->window.window_lower_value < -128 || + config->window.window_upper_value > 127 || + config->window.window_upper_value < -128)) { + /* Invalid value */ + return STATUS_ERR_INVALID_ARG; + } else if (config->window.window_lower_value > 255 || + config->window.window_upper_value > 255){ + /* Invalid value */ + return STATUS_ERR_INVALID_ARG; + } + break; + case ADC_RESOLUTION_10BIT: + if (config->differential_mode && + (config->window.window_lower_value > 511 || + config->window.window_lower_value < -512 || + config->window.window_upper_value > 511 || + config->window.window_upper_value < -512)) { + /* Invalid value */ + return STATUS_ERR_INVALID_ARG; + } else if (config->window.window_lower_value > 1023 || + config->window.window_upper_value > 1023){ + /* Invalid value */ + return STATUS_ERR_INVALID_ARG; + } + break; + case ADC_RESOLUTION_12BIT: + if (config->differential_mode && + (config->window.window_lower_value > 2047 || + config->window.window_lower_value < -2048 || + config->window.window_upper_value > 2047 || + config->window.window_upper_value < -2048)) { + /* Invalid value */ + return STATUS_ERR_INVALID_ARG; + } else if (config->window.window_lower_value > 4095 || + config->window.window_upper_value > 4095){ + /* Invalid value */ + return STATUS_ERR_INVALID_ARG; + } + break; + case ADC_RESOLUTION_16BIT: + if (config->differential_mode && + (config->window.window_lower_value > 32767 || + config->window.window_lower_value < -32768 || + config->window.window_upper_value > 32767 || + config->window.window_upper_value < -32768)) { + /* Invalid value */ + return STATUS_ERR_INVALID_ARG; + } else if (config->window.window_lower_value > 65535 || + config->window.window_upper_value > 65535){ + /* Invalid value */ + return STATUS_ERR_INVALID_ARG; + } + break; + } + } + + /* Configure window mode */ + adc_module->CTRLC.reg |= config->window.window_mode; + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + + /* Configure lower threshold */ + adc_module->WINLT.reg = + config->window.window_lower_value << ADC_WINLT_WINLT_Pos; + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + + /* Configure lower threshold */ + adc_module->WINUT.reg = config->window.window_upper_value << + ADC_WINUT_WINUT_Pos; + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + + /* Configure pin scan mode and positive and negative input pins */ + adc_module->INPUTCTRL.reg = + config->negative_input | + config->positive_input; + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + + /* Configure events */ + adc_module->EVCTRL.reg = config->event_action; + + /* Disable all interrupts */ + adc_module->INTENCLR.reg = + (1 << ADC_INTENCLR_WINMON_Pos) |(1 << ADC_INTENCLR_OVERRUN_Pos) + | (1 << ADC_INTENCLR_RESRDY_Pos); + + if (config->correction.correction_enable){ + /* Make sure gain_correction value is valid */ + if (config->correction.gain_correction > ADC_GAINCORR_GAINCORR_Msk) { + return STATUS_ERR_INVALID_ARG; + } else { + /* Set gain correction value */ + adc_module->GAINCORR.reg = config->correction.gain_correction << + ADC_GAINCORR_GAINCORR_Pos; + } + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + + /* Make sure offset correction value is valid */ + if (config->correction.offset_correction > 2047 || + config->correction.offset_correction < -2048) { + return STATUS_ERR_INVALID_ARG; + } else { + /* Set offset correction value */ + adc_module->OFFSETCORR.reg = config->correction.offset_correction << + ADC_OFFSETCORR_OFFSETCORR_Pos; + } + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + } + + /* Load in the fixed device ADC calibration constants */ + adc_module->CALIB.reg = + ADC_CALIB_BIASREFBUF( + (*(uint32_t *)_adc_biasrefbuf_addr[index] >> _adc_biasrefbuf_pos[index]) + ) | + ADC_CALIB_BIASCOMP( + (*(uint32_t *)_adc_biascomp_addr[index] >> _adc_biascomp_pos[index]) + ); + + return STATUS_OK; +} + +/** + * \brief Initializes the ADC. + * + * Initializes the ADC device struct and the hardware module based on the + * given configuration struct values. + * + * \param[out] module_inst Pointer to the ADC software instance struct + * \param[in] hw Pointer to the ADC module instance + * \param[in] config Pointer to the configuration struct + * + * \return Status of the initialization procedure. + * \retval STATUS_OK The initialization was successful + * \retval STATUS_ERR_INVALID_ARG Invalid argument(s) were provided + * \retval STATUS_BUSY The module is busy with a reset operation + * \retval STATUS_ERR_DENIED The module is enabled + */ +enum status_code adc_init( + struct adc_module *const module_inst, + Adc *hw, + struct adc_config *config) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(hw); + Assert(config); + + /* Temporary variable to hold ADC instance number */ + uint8_t instance = _adc_get_inst_index(hw); + + /* Associate the software module instance with the hardware module */ + module_inst->hw = hw; +#if (SAML22) + /* Turn on the digital interface clock */ + system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, MCLK_APBCMASK_ADC); +#elif (SAML21) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + /* Turn on the digital interface clock */ + system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBD, MCLK_APBDMASK_ADC); +#else + system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, _adc_apbcmasks[instance]); +#endif + + if (hw->CTRLA.reg & ADC_CTRLA_SWRST) { + /* We are in the middle of a reset. Abort. */ + return STATUS_BUSY; + } + + while (adc_is_syncing(module_inst)) { + /* Wait for synchronization */ + } + + if (hw->CTRLA.reg & ADC_CTRLA_ENABLE) { + /* Module must be disabled before initialization. Abort. */ + return STATUS_ERR_DENIED; + } + + /* Store the selected reference for later use */ + module_inst->reference = config->reference; + + /* Make sure the voltage reference is enabled if requested by the config */ + if (module_inst->reference == ADC_REFERENCE_INTREF) { + system_voltage_reference_enable(SYSTEM_VOLTAGE_REFERENCE_OUTPUT); + } + +#if ADC_CALLBACK_MODE == true + for (uint8_t i = 0; i < ADC_CALLBACK_N; i++) { + module_inst->callback[i] = NULL; + }; + + module_inst->registered_callback_mask = 0; + module_inst->enabled_callback_mask = 0; + module_inst->remaining_conversions = 0; + module_inst->job_status = STATUS_OK; + + _adc_instances[instance] = module_inst; + + if (config->event_action == ADC_EVENT_ACTION_DISABLED && + !config->freerunning) { + module_inst->software_trigger = true; + } else { + module_inst->software_trigger = false; + } +#endif + + /* Write configuration to module */ + return _adc_set_config(instance, module_inst, config); +} diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/adc/adc_sam_l_c/adc_callback.c b/src/boards/mcu/samr34/ASF/sam0/drivers/adc/adc_sam_l_c/adc_callback.c new file mode 100644 index 000000000..9b2b9fc1e --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/adc/adc_sam_l_c/adc_callback.c @@ -0,0 +1,254 @@ +/** + * \file + * + * \brief SAM Peripheral Analog-to-Digital Converter Driver + * + * Copyright (c) 2014-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#include "adc_callback.h" + +struct adc_module *_adc_instances[ADC_INST_NUM]; + +static void _adc_interrupt_handler(const uint8_t instance) +{ + struct adc_module *module = _adc_instances[instance]; + + /* get interrupt flags and mask out enabled callbacks */ + uint32_t flags = module->hw->INTFLAG.reg & module->hw->INTENSET.reg; + + if (flags & ADC_INTFLAG_RESRDY) { + /* clear interrupt flag */ + module->hw->INTFLAG.reg = ADC_INTFLAG_RESRDY; + + /* store ADC result in job buffer */ + *(module->job_buffer++) = module->hw->RESULT.reg; + + if (--module->remaining_conversions > 0) { + if (module->software_trigger == true + && (!(module->hw->SEQSTATUS.reg & ADC_SEQSTATUS_SEQBUSY))) { + adc_start_conversion(module); + } + } else { + adc_disable_interrupt(module, ADC_INTERRUPT_RESULT_READY); + if (module->job_status == STATUS_BUSY) { + /* job is complete. update status,disable interrupt + *and call callback */ + module->job_status = STATUS_OK; + + if ((module->enabled_callback_mask & + (1 << ADC_CALLBACK_READ_BUFFER)) && + (module->registered_callback_mask & + (1 << ADC_CALLBACK_READ_BUFFER))) { + (module->callback[ADC_CALLBACK_READ_BUFFER])(module); + } + } + } + } + + if (flags & ADC_INTFLAG_WINMON) { + module->hw->INTFLAG.reg = ADC_INTFLAG_WINMON; + if ((module->enabled_callback_mask & (1 << ADC_CALLBACK_WINDOW)) && + (module->registered_callback_mask & (1 << ADC_CALLBACK_WINDOW))) { + (module->callback[ADC_CALLBACK_WINDOW])(module); + } + + } + + if (flags & ADC_INTFLAG_OVERRUN) { + module->hw->INTFLAG.reg = ADC_INTFLAG_OVERRUN; + if ((module->enabled_callback_mask & (1 << ADC_CALLBACK_ERROR)) && + (module->registered_callback_mask & (1 << ADC_CALLBACK_ERROR))) { + (module->callback[ADC_CALLBACK_ERROR])(module); + } + } +} + +/** Interrupt handler for the ADC module. */ +#if (ADC_INST_NUM > 1) || (SAMC20) +# define _ADC_INTERRUPT_HANDLER(n, m) \ + void ADC##n##_Handler(void) \ + { \ + _adc_interrupt_handler(n); \ + } + + MREPEAT(ADC_INST_NUM, _ADC_INTERRUPT_HANDLER, 0) +#else +void ADC_Handler(void) +{ + _adc_interrupt_handler(0); +} +#endif + +/** + * \brief Registers a callback. + * + * Registers a callback function which is implemented by the user. + * + * \note The callback must be enabled for the interrupt handler to call it + * when the condition for the callback is met. + * + * \param[in] module Pointer to ADC software instance struct + * \param[in] callback_func Pointer to callback function + * \param[in] callback_type Callback type given by an enum + * + */ +void adc_register_callback( + struct adc_module *const module, + adc_callback_t callback_func, + enum adc_callback callback_type) +{ + /* Sanity check arguments */ + Assert(module); + Assert(callback_func); + + /* Register callback function */ + module->callback[callback_type] = callback_func; + + /* Set the bit corresponding to the callback_type */ + module->registered_callback_mask |= (1 << callback_type); +} + +/** + * \brief Unregisters a callback. + * + * Unregisters a callback function which is implemented by the user. + * + * \param[in] module Pointer to ADC software instance struct + * \param[in] callback_type Callback type given by an enum + * + */ +void adc_unregister_callback( + struct adc_module *const module, + enum adc_callback callback_type) +{ + /* Sanity check arguments */ + Assert(module); + + /* Unregister callback function */ + module->callback[callback_type] = NULL; + + /* Clear the bit corresponding to the callback_type */ + module->registered_callback_mask &= ~(1 << callback_type); +} + +/** + * \brief Read multiple samples from ADC. + * + * Read \c samples from the ADC into the \c buffer. + * If there is no hardware trigger defined (event action) the + * driver will retrigger the ADC conversion whenever a conversion + * is complete until \c samples has been acquired. To avoid + * jitter in the sampling frequency using an event trigger is advised. + * + * \param[in] module_inst Pointer to the ADC software instance struct + * \param[in] samples Number of samples to acquire + * \param[out] buffer Buffer to store the ADC samples + * + * \return Status of the job start. + * \retval STATUS_OK The conversion job was started successfully and is + * in progress + * \retval STATUS_BUSY The ADC is already busy with another job + */ +enum status_code adc_read_buffer_job( + struct adc_module *const module_inst, + uint16_t *buffer, + uint16_t samples) +{ + Assert(module_inst); + Assert(samples); + Assert(buffer); + + if(module_inst->remaining_conversions != 0 || + module_inst->job_status == STATUS_BUSY){ + return STATUS_BUSY; + } + + module_inst->job_status = STATUS_BUSY; + module_inst->remaining_conversions = samples; + module_inst->job_buffer = buffer; + + adc_enable_interrupt(module_inst, ADC_INTERRUPT_RESULT_READY); + + if(module_inst->software_trigger == true) { + adc_start_conversion(module_inst); + } + + return STATUS_OK; +} + +/** + * \brief Gets the status of a job. + * + * Gets the status of an ongoing or the last job. + * + * \param [in] module_inst Pointer to the ADC software instance struct + * \param [in] type Type of to get status + * + * \return Status of the job. + */ +enum status_code adc_get_job_status( + struct adc_module *module_inst, + enum adc_job_type type) +{ + /* Sanity check arguments */ + Assert(module_inst); + + if (type == ADC_JOB_READ_BUFFER ) { + return module_inst->job_status; + } else { + return STATUS_ERR_INVALID_ARG; + } +} + +/** + * \brief Aborts an ongoing job. + * + * Aborts an ongoing job. + * + * \param [in] module_inst Pointer to the ADC software instance struct + * \param [in] type Type of job to abort + */ +void adc_abort_job( + struct adc_module *module_inst, + enum adc_job_type type) +{ + /* Sanity check arguments */ + Assert(module_inst); + + if (type == ADC_JOB_READ_BUFFER) { + /* Disable interrupt */ + adc_disable_interrupt(module_inst, ADC_INTERRUPT_RESULT_READY); + /* Mark job as aborted */ + module_inst->job_status = STATUS_ABORTED; + module_inst->remaining_conversions = 0; + } +} + diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/adc/adc_sam_l_c/adc_feature.h b/src/boards/mcu/samr34/ASF/sam0/drivers/adc/adc_sam_l_c/adc_feature.h new file mode 100644 index 000000000..243b91706 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/adc/adc_sam_l_c/adc_feature.h @@ -0,0 +1,727 @@ +/** + * \file + * + * \brief SAM ADC functionality + * + * Copyright (c) 2014-2020 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#ifndef ADC_FEATURE_H_INCLUDED +#define ADC_FEATURE_H_INCLUDED + +/** + * \addtogroup asfdoc_sam0_adc_group + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/*@{*/ +#if (SAMC20) || (SAMC21) || defined(__DOXYGEN__) +/** Output Driver Strength Selection feature support. */ +# define FEATURE_ADC_SUPPORT_MASTER_SLAVE +#endif +/*@}*/ + +#if ADC_CALLBACK_MODE == true +# include + +#if !defined(__DOXYGEN__) +extern struct adc_module *_adc_instances[ADC_INST_NUM]; +#endif + +/** Forward definition of the device instance. */ +struct adc_module; + +/** Type of the callback functions. */ +typedef void (*adc_callback_t)(struct adc_module *const module); + +/** + * \brief ADC callback enum. + * + * Callback types for ADC callback driver. + * + */ +enum adc_callback { + /** Callback for buffer received */ + ADC_CALLBACK_READ_BUFFER, + /** Callback when window is hit */ + ADC_CALLBACK_WINDOW, + /** Callback for error */ + ADC_CALLBACK_ERROR, +# if !defined(__DOXYGEN__) + /** Number of available callbacks */ + ADC_CALLBACK_N, +# endif +}; + +#endif + +/** + * \brief ADC reference voltage enum. + * + * Enum for the possible reference voltages for the ADC. + * + */ +enum adc_reference { + /** Internal Bandgap Reference */ + ADC_REFERENCE_INTREF = ADC_REFCTRL_REFSEL_INTREF, + /** 1/1.48VCC reference */ + ADC_REFERENCE_INTVCC0 = ADC_REFCTRL_REFSEL_INTVCC0, + /** 1/2VCC (only for internal VCC > 2.1V) */ + ADC_REFERENCE_INTVCC1 = ADC_REFCTRL_REFSEL_INTVCC1, + /** External reference A */ + ADC_REFERENCE_AREFA = ADC_REFCTRL_REFSEL_AREFA, +#if (SAML21) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + /** External reference B */ + ADC_REFERENCE_AREFB = ADC_REFCTRL_REFSEL_AREFB, +#endif +#if (SAMC20) || (SAMC21) + /** DAC */ + ADC_REFERENCE_DAC = ADC_REFCTRL_REFSEL_DAC, +#endif + /** VDDANA */ + ADC_REFERENCE_INTVCC2 = ADC_REFCTRL_REFSEL_INTVCC2, +}; + +/** + * \brief ADC clock prescaler enum. + * + * Enum for the possible clock prescaler values for the ADC. + * + */ +enum adc_clock_prescaler { + /** ADC clock division factor 2 */ + ADC_CLOCK_PRESCALER_DIV2 = ADC_CTRLB_PRESCALER_DIV2, + /** ADC clock division factor 4 */ + ADC_CLOCK_PRESCALER_DIV4 = ADC_CTRLB_PRESCALER_DIV4, + /** ADC clock division factor 8 */ + ADC_CLOCK_PRESCALER_DIV8 = ADC_CTRLB_PRESCALER_DIV8, + /** ADC clock division factor 16 */ + ADC_CLOCK_PRESCALER_DIV16 = ADC_CTRLB_PRESCALER_DIV16, + /** ADC clock division factor 32 */ + ADC_CLOCK_PRESCALER_DIV32 = ADC_CTRLB_PRESCALER_DIV32, + /** ADC clock division factor 64 */ + ADC_CLOCK_PRESCALER_DIV64 = ADC_CTRLB_PRESCALER_DIV64, + /** ADC clock division factor 128 */ + ADC_CLOCK_PRESCALER_DIV128 = ADC_CTRLB_PRESCALER_DIV128, + /** ADC clock division factor 256 */ + ADC_CLOCK_PRESCALER_DIV256 = ADC_CTRLB_PRESCALER_DIV256, +}; + +/** + * \brief ADC resolution enum. + * + * Enum for the possible resolution values for the ADC. + * + */ +enum adc_resolution { + /** ADC 12-bit resolution */ + ADC_RESOLUTION_12BIT = ADC_CTRLC_RESSEL_12BIT, + /** ADC 16-bit resolution using oversampling and decimation */ + ADC_RESOLUTION_16BIT = ADC_CTRLC_RESSEL_16BIT, + /** ADC 10-bit resolution */ + ADC_RESOLUTION_10BIT = ADC_CTRLC_RESSEL_10BIT, + /** ADC 8-bit resolution */ + ADC_RESOLUTION_8BIT = ADC_CTRLC_RESSEL_8BIT, + /** ADC 13-bit resolution using oversampling and decimation */ + ADC_RESOLUTION_13BIT, + /** ADC 14-bit resolution using oversampling and decimation */ + ADC_RESOLUTION_14BIT, + /** ADC 15-bit resolution using oversampling and decimation */ + ADC_RESOLUTION_15BIT, + /** ADC 16-bit result register for use with averaging. When using this mode + * the ADC result register will be set to 16-bit wide, and the number of + * samples to accumulate and the division factor is configured by the + * \ref adc_config.accumulate_samples and \ref adc_config.divide_result + * members in the configuration struct. + */ + ADC_RESOLUTION_CUSTOM, +}; + +/** + * \brief ADC window monitor mode enum. + * + * Enum for the possible window monitor modes for the ADC. + * + */ +enum adc_window_mode { + /** No window mode */ + ADC_WINDOW_MODE_DISABLE = ADC_CTRLC_WINMODE_DISABLE, + /** RESULT > WINLT */ + ADC_WINDOW_MODE_ABOVE_LOWER = ADC_CTRLC_WINMODE_MODE1, + /** RESULT < WINUT */ + ADC_WINDOW_MODE_BELOW_UPPER = ADC_CTRLC_WINMODE_MODE2, + /** WINLT < RESULT < WINUT */ + ADC_WINDOW_MODE_BETWEEN = ADC_CTRLC_WINMODE_MODE3, + /** !(WINLT < RESULT < WINUT) */ + ADC_WINDOW_MODE_BETWEEN_INVERTED = ADC_CTRLC_WINMODE_MODE4, +}; + +/** + * \brief ADC event action enum. + * + * Enum for the possible actions to take on an incoming event. + * + */ +enum adc_event_action { + /** Event action disabled */ + ADC_EVENT_ACTION_DISABLED = 0, + /** Flush ADC and start conversion */ + ADC_EVENT_ACTION_FLUSH_START_CONV = ADC_EVCTRL_FLUSHEI, + /** Start conversion */ + ADC_EVENT_ACTION_START_CONV = ADC_EVCTRL_STARTEI, +}; + +/** + * \brief ADC positive MUX input selection enum. + * + * Enum for the possible positive MUX input selections for the ADC. + * + */ +enum adc_positive_input { + /** ADC0 pin */ + ADC_POSITIVE_INPUT_PIN0 = ADC_INPUTCTRL_MUXPOS_AIN0, + /** ADC1 pin */ + ADC_POSITIVE_INPUT_PIN1 = ADC_INPUTCTRL_MUXPOS_AIN1, + /** ADC2 pin */ + ADC_POSITIVE_INPUT_PIN2 = ADC_INPUTCTRL_MUXPOS_AIN2, + /** ADC3 pin */ + ADC_POSITIVE_INPUT_PIN3 = ADC_INPUTCTRL_MUXPOS_AIN3, + /** ADC4 pin */ + ADC_POSITIVE_INPUT_PIN4 = ADC_INPUTCTRL_MUXPOS_AIN4, + /** ADC5 pin */ + ADC_POSITIVE_INPUT_PIN5 = ADC_INPUTCTRL_MUXPOS_AIN5, + /** ADC6 pin */ + ADC_POSITIVE_INPUT_PIN6 = ADC_INPUTCTRL_MUXPOS_AIN6, + /** ADC7 pin */ + ADC_POSITIVE_INPUT_PIN7 = ADC_INPUTCTRL_MUXPOS_AIN7, + /** ADC8 pin */ + ADC_POSITIVE_INPUT_PIN8 = ADC_INPUTCTRL_MUXPOS_AIN8, + /** ADC9 pin */ + ADC_POSITIVE_INPUT_PIN9 = ADC_INPUTCTRL_MUXPOS_AIN9, + /** ADC10 pin */ + ADC_POSITIVE_INPUT_PIN10 = ADC_INPUTCTRL_MUXPOS_AIN10, + /** ADC11 pin */ + ADC_POSITIVE_INPUT_PIN11 = ADC_INPUTCTRL_MUXPOS_AIN11, +#if !(SAMC20) && !(SAMC21) + /** ADC12 pin */ + ADC_POSITIVE_INPUT_PIN12 = ADC_INPUTCTRL_MUXPOS_AIN12, + /** ADC13 pin */ + ADC_POSITIVE_INPUT_PIN13 = ADC_INPUTCTRL_MUXPOS_AIN13, + /** ADC14 pin */ + ADC_POSITIVE_INPUT_PIN14 = ADC_INPUTCTRL_MUXPOS_AIN14, + /** ADC15 pin */ + ADC_POSITIVE_INPUT_PIN15 = ADC_INPUTCTRL_MUXPOS_AIN15, + /** ADC16 pin */ + ADC_POSITIVE_INPUT_PIN16 = ADC_INPUTCTRL_MUXPOS_AIN16, + /** ADC17 pin */ + ADC_POSITIVE_INPUT_PIN17 = ADC_INPUTCTRL_MUXPOS_AIN17, + /** ADC18 pin */ + ADC_POSITIVE_INPUT_PIN18 = ADC_INPUTCTRL_MUXPOS_AIN18, + /** ADC19 pin */ + ADC_POSITIVE_INPUT_PIN19 = ADC_INPUTCTRL_MUXPOS_AIN19, +#if !(SAML22 || SAMR30 || SAMR34 || SAMR35 || (WLR089)) + /** ADC20 pin. */ + ADC_POSITIVE_INPUT_PIN20 = ADC_INPUTCTRL_MUXPOS_AIN20, + /** ADC21 pin */ + ADC_POSITIVE_INPUT_PIN21 = ADC_INPUTCTRL_MUXPOS_AIN21, + /** ADC22 pin */ + ADC_POSITIVE_INPUT_PIN22 = ADC_INPUTCTRL_MUXPOS_AIN22, + /** ADC23 pin */ + ADC_POSITIVE_INPUT_PIN23 = ADC_INPUTCTRL_MUXPOS_AIN23, +#endif + /** Temperature reference. */ + ADC_POSITIVE_INPUT_TEMP = ADC_INPUTCTRL_MUXPOS_TEMP, +#endif + /** Bandgap voltage */ + ADC_POSITIVE_INPUT_BANDGAP = ADC_INPUTCTRL_MUXPOS_BANDGAP, + /** 1/4 scaled core supply */ + ADC_POSITIVE_INPUT_SCALEDCOREVCC = ADC_INPUTCTRL_MUXPOS_SCALEDCOREVCC, + /** 1/4 scaled I/O supply */ + ADC_POSITIVE_INPUT_SCALEDIOVCC = ADC_INPUTCTRL_MUXPOS_SCALEDIOVCC, +#if !(SAML22|| SAMR30 || SAMR34 || SAMR35 || (WLR089)) + /** DAC input */ + ADC_POSITIVE_INPUT_DAC = ADC_INPUTCTRL_MUXPOS_DAC, +#endif + +#if (SAML21) + /** SCALEDVBAT */ + ADC_POSITIVE_INPUT_SCALEDVBAT = ADC_INPUTCTRL_MUXPOS_SCALEDVBAT, + /** OPAMP01 */ + ADC_POSITIVE_INPUT_OPAMP01 = ADC_INPUTCTRL_MUXPOS_OPAMP01, + /** OPAMP02 */ + ADC_POSITIVE_INPUT_OPAMP2 = ADC_INPUTCTRL_MUXPOS_OPAMP2, +#endif +#if (SAML22) + /** SCALEDVBAT */ + ADC_POSITIVE_INPUT_SCALEDVBAT = ADC_INPUTCTRL_MUXPOS_SCALEDVBAT, + /** CTAT. */ + ADC_POSITIVE_INPUT_CTAT = ADC_INPUTCTRL_MUXPOS_CTAT, +#endif +}; + +/** + * \brief ADC negative MUX input selection enum. + * + * Enum for the possible negative MUX input selections for the ADC. + * + */ +enum adc_negative_input { + /** ADC0 pin */ + ADC_NEGATIVE_INPUT_PIN0 = ADC_INPUTCTRL_MUXNEG_AIN0, + /** ADC1 pin */ + ADC_NEGATIVE_INPUT_PIN1 = ADC_INPUTCTRL_MUXNEG_AIN1, + /** ADC2 pin */ + ADC_NEGATIVE_INPUT_PIN2 = ADC_INPUTCTRL_MUXNEG_AIN2, + /** ADC3 pin */ + ADC_NEGATIVE_INPUT_PIN3 = ADC_INPUTCTRL_MUXNEG_AIN3, + /** ADC4 pin */ + ADC_NEGATIVE_INPUT_PIN4 = ADC_INPUTCTRL_MUXNEG_AIN4, + /** ADC5 pin */ + ADC_NEGATIVE_INPUT_PIN5 = ADC_INPUTCTRL_MUXNEG_AIN5, +#if !(SAMC20) && !(SAMC21) && !(SAMR30) && !(SAMR34) && !(SAMR35) && !(WLR089) + /** ADC6 pin */ + ADC_NEGATIVE_INPUT_PIN6 = ADC_INPUTCTRL_MUXNEG_AIN6, + /** ADC7 pin */ + ADC_NEGATIVE_INPUT_PIN7 = ADC_INPUTCTRL_MUXNEG_AIN7, +#endif + /** Internal ground */ + ADC_NEGATIVE_INPUT_GND = ADC_INPUTCTRL_MUXNEG(0x18u), +}; + +/** + * \brief ADC number of accumulated samples enum. + * + * Enum for the possible numbers of ADC samples to accumulate. + * This setting is only used when the \ref ADC_RESOLUTION_CUSTOM + * resolution setting is used. + * + */ +enum adc_accumulate_samples { + /** No averaging */ + ADC_ACCUMULATE_DISABLE = ADC_AVGCTRL_SAMPLENUM_1, + /** Average 2 samples */ + ADC_ACCUMULATE_SAMPLES_2 = ADC_AVGCTRL_SAMPLENUM_2, + /** Average 4 samples */ + ADC_ACCUMULATE_SAMPLES_4 = ADC_AVGCTRL_SAMPLENUM_4, + /** Average 8 samples */ + ADC_ACCUMULATE_SAMPLES_8 = ADC_AVGCTRL_SAMPLENUM_8, + /** Average 16 samples */ + ADC_ACCUMULATE_SAMPLES_16 = ADC_AVGCTRL_SAMPLENUM_16, + /** Average 32 samples */ + ADC_ACCUMULATE_SAMPLES_32 = ADC_AVGCTRL_SAMPLENUM_32, + /** Average 64 samples */ + ADC_ACCUMULATE_SAMPLES_64 = ADC_AVGCTRL_SAMPLENUM_64, + /** Average 128 samples */ + ADC_ACCUMULATE_SAMPLES_128 = ADC_AVGCTRL_SAMPLENUM_128, + /** Average 256 samples */ + ADC_ACCUMULATE_SAMPLES_256 = ADC_AVGCTRL_SAMPLENUM_256, + /** Average 512 samples */ + ADC_ACCUMULATE_SAMPLES_512 = ADC_AVGCTRL_SAMPLENUM_512, + /** Average 1024 samples */ + ADC_ACCUMULATE_SAMPLES_1024 = ADC_AVGCTRL_SAMPLENUM_1024, +}; + +/** + * \brief ADC possible dividers for the result register. + * + * Enum for the possible division factors to use when accumulating + * multiple samples. To keep the same resolution for the averaged + * result and the actual input value, the division factor must + * be equal to the number of samples accumulated. This setting is only + * used when the \ref ADC_RESOLUTION_CUSTOM resolution setting is used. + */ +enum adc_divide_result { + /** Don't divide result register after accumulation */ + ADC_DIVIDE_RESULT_DISABLE = 0, + /** Divide result register by 2 after accumulation */ + ADC_DIVIDE_RESULT_2 = 1, + /** Divide result register by 4 after accumulation */ + ADC_DIVIDE_RESULT_4 = 2, + /** Divide result register by 8 after accumulation */ + ADC_DIVIDE_RESULT_8 = 3, + /** Divide result register by 16 after accumulation */ + ADC_DIVIDE_RESULT_16 = 4, + /** Divide result register by 32 after accumulation */ + ADC_DIVIDE_RESULT_32 = 5, + /** Divide result register by 64 after accumulation */ + ADC_DIVIDE_RESULT_64 = 6, + /** Divide result register by 128 after accumulation */ + ADC_DIVIDE_RESULT_128 = 7, +}; + +#if ADC_CALLBACK_MODE == true +/** + * Enum for the possible ADC interrupt flags. + */ +enum adc_interrupt_flag { + /** ADC result ready */ + ADC_INTERRUPT_RESULT_READY = ADC_INTFLAG_RESRDY, + /** Window monitor match */ + ADC_INTERRUPT_WINDOW = ADC_INTFLAG_WINMON, + /** ADC result overwritten before read */ + ADC_INTERRUPT_OVERRUN = ADC_INTFLAG_OVERRUN, +}; +#endif + +/** + * \brief ADC oversampling and decimation enum. + * + * Enum for the possible numbers of bits resolution can be increased by when + * using oversampling and decimation. + * + */ +enum adc_oversampling_and_decimation { + /** Don't use oversampling and decimation mode */ + ADC_OVERSAMPLING_AND_DECIMATION_DISABLE = 0, + /** 1-bit resolution increase */ + ADC_OVERSAMPLING_AND_DECIMATION_1BIT, + /** 2-bit resolution increase */ + ADC_OVERSAMPLING_AND_DECIMATION_2BIT, + /** 3-bit resolution increase */ + ADC_OVERSAMPLING_AND_DECIMATION_3BIT, + /** 4-bit resolution increase */ + ADC_OVERSAMPLING_AND_DECIMATION_4BIT +}; + +#ifdef FEATURE_ADC_SUPPORT_MASTER_SLAVE +/** + * Enum for the trigger selection in dual mode. + */ +enum adc_dual_mode_trigger_selection { + /** Start event or software trigger will start a conversion on both ADCs */ + ADC_DUAL_MODE_BOTH = ADC_CTRLC_DUALSEL_BOTH, + /** START event or software trigger will alternatingly start a conversion on ADC0 and ADC1 */ + ADC_DUAL_MODE_INTERLEAVE = ADC_CTRLC_DUALSEL_INTERLEAVE, +}; +#endif + +/** + * \brief Window monitor configuration structure. + * + * Window monitor configuration structure. + */ +struct adc_window_config { + /** Selected window mode */ + enum adc_window_mode window_mode; + /** Lower window value */ + int32_t window_lower_value; + /** Upper window value */ + int32_t window_upper_value; +}; + +/** + * \brief ADC event enable/disable structure. + * + * Event flags for the ADC module. This is used to enable and + * disable events via \ref adc_enable_events() and \ref adc_disable_events(). + */ +struct adc_events { + /** Enable event generation on conversion done */ + bool generate_event_on_conversion_done; + /** Enable event generation on window monitor */ + bool generate_event_on_window_monitor; +}; + +/** + * \brief Gain and offset correction configuration structure. + * + * Gain and offset correction configuration structure. + * Part of the \ref adc_config struct and will be initialized by + * \ref adc_get_config_defaults. + */ +struct adc_correction_config { + /** + * Enables correction for gain and offset based on values of gain_correction and + * offset_correction if set to true + */ + bool correction_enable; + /** + * This value defines how the ADC conversion result is compensated for gain + * error before written to the result register. This is a fractional value, + * 1-bit integer plus an 11-bit fraction, therefore + * 1/2 <= gain_correction < 2. Valid \c gain_correction values ranges from + * \c 0b010000000000 to \c 0b111111111111. + */ + uint16_t gain_correction; + /** + * This value defines how the ADC conversion result is compensated for + * offset error before written to the result register. This is a 12-bit + * value in two's complement format. + */ + int16_t offset_correction; +}; + +/** + * \brief ADC configuration structure. + * + * Configuration structure for an ADC instance. This structure should be + * initialized by the \ref adc_get_config_defaults() + * function before being modified by the user application. + */ +struct adc_config { + /** GCLK generator used to clock the peripheral */ + enum gclk_generator clock_source; + /** Voltage reference */ + enum adc_reference reference; + /** Clock prescaler */ + enum adc_clock_prescaler clock_prescaler; + /** Result resolution */ + enum adc_resolution resolution; + /** Positive MUX input */ + enum adc_positive_input positive_input; + /** Negative MUX input */ + enum adc_negative_input negative_input; + /** Number of ADC samples to accumulate when using the + * \c ADC_RESOLUTION_CUSTOM mode + */ + enum adc_accumulate_samples accumulate_samples; + /** Division ration when using the ADC_RESOLUTION_CUSTOM mode */ + enum adc_divide_result divide_result; + /** Left adjusted result */ + bool left_adjust; + /** Enables differential mode if true */ + bool differential_mode; + /** Enables free running mode if true */ + bool freerunning; + /** ADC run in standby control */ + bool run_in_standby; + /** ADC On demand control */ + bool on_demand; + /** + * Enables sampling period offset compensation if true + */ + bool sampling_time_compensation_enable; + /** + * Positive input enabled mask for conversion sequence. + * The sequence start from the lowest input, and go to the next enabled input + * automatically when the conversion is done. If no bits are set the + * sequence is disabled. + */ + uint32_t positive_input_sequence_mask_enable; + /** + * Enables reference buffer offset compensation if true. + * This will increase the accuracy of the gain stage, but decreases the input + * impedance; therefore the startup time of the reference must be increased. + */ + bool reference_compensation_enable; + /** + * This value (0-63) control the ADC sampling time in number of half ADC + * prescaled clock cycles (depends of \c ADC_PRESCALER value), thus + * controlling the ADC input impedance. Sampling time is set according to + * the formula: + * Sample time = (sample_length+1) * (ADCclk / 2). + */ + uint8_t sample_length; + /** Window monitor configuration structure */ + struct adc_window_config window; + /** Gain and offset correction configuration structure */ + struct adc_correction_config correction; + /** Event action to take on incoming event */ + enum adc_event_action event_action; +}; + +/** + * \brief ADC software device instance structure. + * + * ADC software instance structure, used to retain software state information + * of an associated hardware module instance. + * + * \note The fields of this structure should not be altered by the user + * application; they are reserved for module-internal use only. + */ +struct adc_module { +#if !defined(__DOXYGEN__) + /** Pointer to ADC hardware module */ + Adc *hw; + /** Keep reference configuration so we know when enable is called */ + enum adc_reference reference; +# if ADC_CALLBACK_MODE == true + /** Array to store callback functions */ + adc_callback_t callback[ADC_CALLBACK_N]; + /** Pointer to buffer used for ADC results */ + volatile uint16_t *job_buffer; + /** Remaining number of conversions in current job */ + volatile uint16_t remaining_conversions; + /** Bit mask for callbacks registered */ + uint8_t registered_callback_mask; + /** Bit mask for callbacks enabled */ + uint8_t enabled_callback_mask; + /** Holds the status of the ongoing or last conversion job */ + volatile enum status_code job_status; + /** If software triggering is needed */ + bool software_trigger; +# endif +#endif +}; + +#if !defined(__DOXYGEN__) + +/** + * \brief Determines if the hardware module(s) are currently synchronizing to the bus. + * + * Checks to see if the underlying hardware peripheral module(s) are currently + * synchronizing across multiple clock domains to the hardware bus. This + * function can be used to delay further operations on a module until such time + * that it is ready, to prevent blocking delays for synchronization in the + * user application. + * + * \param[in] module_inst Pointer to the ADC software instance struct + * + * \return Synchronization status of the underlying hardware module(s). + * + * \retval true if the module synchronization is ongoing + * \retval false if the module has completed synchronization + */ +static inline bool adc_is_syncing( + struct adc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + + Adc *const adc_module = module_inst->hw; + + if (adc_module->SYNCBUSY.reg) { + return true; + } + + return false; +} +#endif + +/** + * \name Positive Input Sequence + * @{ + */ + +/** + * \brief Enable positive input sequence mask for conversion. + * + * The sequence start from the lowest input, and go to the next enabled input + * automatically when the conversion is done. If no bits are set the + * sequence is disabled. + * + * \param[in] module_inst Pointer to the ADC software instance struct + * \param[in] eanble_seq_mask Sequence mask + */ +static inline void adc_enable_positive_input_sequence( + struct adc_module *const module_inst, + uint32_t positive_input_sequence_mask_enable) +{ + /* Sanity check arguments */ + Assert(module_inst); + + Adc *const adc_module = module_inst->hw; + adc_module->SEQCTRL.reg = positive_input_sequence_mask_enable; +} + +/** + * \brief Disable positive input in the sequence. + * + * Disable positive input in the sequence. + * + * \param[in] module_inst Pointer to the ADC software instance struct + */ +static inline void adc_disable_positive_input_sequence( + struct adc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + + Adc *const adc_module = module_inst->hw; + adc_module->SEQCTRL.reg = 0; +} + +/** + * \brief Get ADC sequence status. + * + * Check if a sequence is done and get last conversion done in the sequence. + * + * \param[in] module_inst Pointer to the ADC software instance struct + * \param[out] is_sequence_busy Sequence busy status + * \param[out] sequence_state This value identifies the last conversion + * done in the sequence + */ +static inline void adc_get_sequence_status( + struct adc_module *const module_inst, + bool * is_sequence_busy, + uint8_t *sequence_state) +{ + /* Sanity check arguments */ + Assert(module_inst); + uint8_t temp = false; + Adc *const adc_module = module_inst->hw; + temp = adc_module->SEQSTATUS.reg; + if(temp & ADC_SEQSTATUS_SEQBUSY){ + *is_sequence_busy = true; + } + *sequence_state = temp & ADC_SEQSTATUS_SEQSTATE_Msk; +} + +/** @} */ + +#ifdef FEATURE_ADC_SUPPORT_MASTER_SLAVE +/** + * \brief Set ADC master and slave mode. + * + * Enable ADC module Master-Slave Operation and select dual mode trigger. + * + * \param[in] master_inst Pointer to the master ADC software instance struct + * \param[in] slave_inst Pointer to the slave ADC software instance struct + * \param[in] dualsel Dual mode trigger selection + * + */ +static inline void adc_set_master_slave_mode( + struct adc_module *const master_inst, + struct adc_module *const slave_inst, + enum adc_dual_mode_trigger_selection dualsel) +{ + /* Sanity check arguments */ + Assert(master_inst); + Assert(slave_inst); + + slave_inst->hw->CTRLA.reg |= ADC_CTRLA_SLAVEEN; + master_inst->hw->CTRLC.reg |= dualsel; + +}; +#endif +/** @} */ + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif /* ADC_FEATURE_H_INCLUDED */ + diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/extint/extint.h b/src/boards/mcu/samr34/ASF/sam0/drivers/extint/extint.h new file mode 100644 index 000000000..f4e95e3e1 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/extint/extint.h @@ -0,0 +1,699 @@ +/** + * \file + * + * \brief SAM External Interrupt Driver + * + * Copyright (c) 2012-2020 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#ifndef EXTINT_H_INCLUDED +#define EXTINT_H_INCLUDED + +/** + * \defgroup asfdoc_sam0_extint_group SAM External Interrupt (EXTINT) Driver + * + * This driver for Atmel® | SMART ARM®-based microcontrollers provides + * an interface for the configuration and management of external interrupts + * generated by the physical device pins, including edge detection. + * The following driver API modes are covered by this + * manual: + * + * - Polled APIs + * \if EXTINT_CALLBACK_MODE + * - Callback APIs + * \endif + * + * The following peripheral is used by this module: + * - EIC (External Interrupt Controller) + * + * The following devices can use this module: + * - Atmel | SMART SAM D20/D21 + * - Atmel | SMART SAM R21 + * - Atmel | SMART SAM D09/D10/D11 + * - Atmel | SMART SAM L21/L22 + * - Atmel | SMART SAM DA1 + * - Atmel | SMART SAM C20/C21 + * - Atmel | SMART SAM HA1 + * - Atmel | SMART SAM R34/R35 + * + * The outline of this documentation is as follows: + * - \ref asfdoc_sam0_extint_prerequisites + * - \ref asfdoc_sam0_extint_module_overview + * - \ref asfdoc_sam0_extint_special_considerations + * - \ref asfdoc_sam0_extint_extra_info + * - \ref asfdoc_sam0_extint_examples + * - \ref asfdoc_sam0_extint_api_overview + * + * + * \section asfdoc_sam0_extint_prerequisites Prerequisites + * + * There are no prerequisites for this module. + * + * + * \section asfdoc_sam0_extint_module_overview Module Overview + * + * The External Interrupt (EXTINT) module provides a method of asynchronously + * detecting rising edge, falling edge, or specific level detection on individual + * I/O pins of a device. This detection can then be used to trigger a software + * interrupt or event, or polled for later use if required. External interrupts + * can also optionally be used to automatically wake up the device from sleep + * mode, allowing the device to conserve power while still being able to react + * to an external stimulus in a timely manner. + * + * \subsection asfdoc_sam0_extint_logical_channels Logical Channels + * The External Interrupt module contains a number of logical channels, each of + * which is capable of being individually configured for a given pin routing, + * detection mode, and filtering/wake up characteristics. + * + * Each individual logical external interrupt channel may be routed to a single + * physical device I/O pin in order to detect a particular edge or level of the + * incoming signal. + * + * \subsection asfdoc_sam0_extint_module_overview_nmi_chanel NMI Channels + * + * One or more Non Maskable Interrupt (NMI) channels are provided within each + * physical External Interrupt Controller module, allowing a single physical pin + * of the device to fire a single NMI interrupt in response to a particular + * edge or level stimulus. An NMI cannot, as the name suggests, be disabled in + * firmware and will take precedence over any in-progress interrupt sources. + * + * NMIs can be used to implement critical device features such as forced + * software reset or other functionality where the action should be executed in + * preference to all other running code with a minimum amount of latency. + * + * \subsection asfdoc_sam0_extint_module_overview_filtering Input Filtering and Detection + * + * To reduce the possibility of noise or other transient signals causing + * unwanted device wake-ups, interrupts, and/or events via an external interrupt + * channel. A hardware signal filter can be enabled on individual channels. This + * filter provides a Majority-of-Three voter filter on the incoming signal, so + * that the input state is considered to be the majority vote of three + * subsequent samples of the pin input buffer. The possible sampled input and + * resulting filtered output when the filter is enabled is shown in + * \ref asfdoc_sam0_extint_filter_table "the table below". + * + * \anchor asfdoc_sam0_extint_filter_table + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Sampled Input and Resulting Filtered Output
Input Sample 1Input Sample 2Input Sample 3Filtered Output
0 0 0 0
0 0 1 0
0 1 0 0
0 1 1 1
1 0 0 0
1 0 1 1
1 1 0 1
1 1 1 1
+ * + * \subsection asfdoc_sam0_extint_module_overview_events Events and Interrupts + * + * Channel detection states may be polled inside the application for synchronous + * detection, or events and interrupts may be used for asynchronous behavior. + * Each channel can be configured to give an asynchronous hardware event (which + * may in turn trigger actions in other hardware modules) or an asynchronous + * software interrupt. + * + * \note The connection of events between modules requires the use of the + * \ref asfdoc_sam0_events_group "SAM Event System Driver (EVENTS)" + * to route output event of one module to the input event of another. + * For more information on event routing, refer to the event driver + * documentation. + * + * \subsection asfdoc_sam0_extint_module_overview_physical Physical Connection + * + * \ref asfdoc_sam0_extint_int_connections "The diagram below" shows how this + * module is interconnected within the device. + * + * \anchor asfdoc_sam0_extint_int_connections + * \dot + * digraph overview { + * node [label="Port Pad" shape=square] pad; + * + * subgraph driver { + * node [label="Peripheral MUX" shape=trapezium] pinmux; + * node [label="EIC Module" shape=ellipse] eic; + * node [label="Other Peripheral Modules" shape=ellipse style=filled fillcolor=lightgray] peripherals; + * } + * + * pinmux -> eic; + * pad -> pinmux; + * pinmux -> peripherals; + * } + * \enddot + * + * \section asfdoc_sam0_extint_special_considerations Special Considerations + * + * Not all devices support disabling of the NMI channel(s) detection mode - see + * your device datasheet. + * + * + * \section asfdoc_sam0_extint_extra_info Extra Information + * + * For extra information, see \ref asfdoc_sam0_extint_extra. This includes: + * - \ref asfdoc_sam0_extint_extra_acronyms + * - \ref asfdoc_sam0_extint_extra_dependencies + * - \ref asfdoc_sam0_extint_extra_errata + * - \ref asfdoc_sam0_extint_extra_history + * + * + * \section asfdoc_sam0_extint_examples Examples + * + * For a list of examples related to this driver, see + * \ref asfdoc_sam0_extint_exqsg. + * + * + * \section asfdoc_sam0_extint_api_overview API Overview + * @{ + */ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief External interrupt edge detection configuration enum. + * + * Enum for the possible signal edge detection modes of the External + * Interrupt Controller module. + */ +enum extint_detect { + /** No edge detection. Not allowed as a NMI detection mode on some + * devices. */ + EXTINT_DETECT_NONE = 0, + /** Detect rising signal edges */ + EXTINT_DETECT_RISING = 1, + /** Detect falling signal edges */ + EXTINT_DETECT_FALLING = 2, + /** Detect both signal edges */ + EXTINT_DETECT_BOTH = 3, + /** Detect high signal levels */ + EXTINT_DETECT_HIGH = 4, + /** Detect low signal levels */ + EXTINT_DETECT_LOW = 5, +}; + +/** + * \brief External interrupt internal pull configuration enum. + * + * Enum for the possible pin internal pull configurations. + * + * \note Disabling the internal pull resistor is not recommended if the driver + * is used in interrupt (callback) mode, due the possibility of floating + * inputs generating continuous interrupts. + */ +enum extint_pull { + /** Internal pull-up resistor is enabled on the pin */ + EXTINT_PULL_UP = SYSTEM_PINMUX_PIN_PULL_UP, + /** Internal pull-down resistor is enabled on the pin */ + EXTINT_PULL_DOWN = SYSTEM_PINMUX_PIN_PULL_DOWN, + /** Internal pull resistor is disconnected from the pin */ + EXTINT_PULL_NONE = SYSTEM_PINMUX_PIN_PULL_NONE, +}; + +/** The EIC is clocked by GCLK_EIC. */ +#define EXTINT_CLK_GCLK 0 +/** The EIC is clocked by CLK_ULP32K. */ +#define EXTINT_CLK_ULP32K 1 + +/** + * \brief External Interrupt Controller channel configuration structure. + * + * Configuration structure for the edge detection mode of an external + * interrupt channel. + */ +struct extint_chan_conf { + /** GPIO pin the NMI should be connected to */ + uint32_t gpio_pin; + /** MUX position the GPIO pin should be configured to */ + uint32_t gpio_pin_mux; + /** Internal pull to enable on the input pin */ + enum extint_pull gpio_pin_pull; +#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + /** Enable asynchronous edge detection. */ + bool enable_async_edge_detection; +#else + /** Wake up the device if the channel interrupt fires during sleep mode */ + bool wake_if_sleeping; +#endif + /** Filter the raw input signal to prevent noise from triggering an + * interrupt accidentally, using a three sample majority filter */ + bool filter_input_signal; + /** Edge detection mode to use */ + enum extint_detect detection_criteria; +}; + +/** + * \brief External Interrupt event enable/disable structure. + * + * Event flags for the \ref extint_enable_events() and + * \ref extint_disable_events(). + */ +struct extint_events { + /** If \c true, an event will be generated when an external interrupt + * channel detection state changes */ + bool generate_event_on_detect[32 * EIC_INST_NUM]; +}; + +/** + * \brief External Interrupt Controller NMI configuration structure. + * + * Configuration structure for the edge detection mode of an external + * interrupt NMI channel. + */ +struct extint_nmi_conf { + /** GPIO pin the NMI should be connected to */ + uint32_t gpio_pin; + /** MUX position the GPIO pin should be configured to */ + uint32_t gpio_pin_mux; + /** Internal pull to enable on the input pin */ + enum extint_pull gpio_pin_pull; + /** Filter the raw input signal to prevent noise from triggering an + * interrupt accidentally, using a three sample majority filter */ + bool filter_input_signal; + /** Edge detection mode to use. Not all devices support all possible + * detection modes for NMIs. + */ + enum extint_detect detection_criteria; +#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + /** Enable asynchronous edge detection. */ + bool enable_async_edge_detection; +#endif +}; + +#if EXTINT_CALLBACK_MODE == true +/** Type definition for an EXTINT module callback function */ +typedef void (*extint_callback_t)(void); + +#ifndef EIC_NUMBER_OF_INTERRUPTS +# define EIC_NUMBER_OF_INTERRUPTS 16 +#endif +#endif + +#if !defined(__DOXYGEN__) +/** \internal + * Internal EXTINT module device instance structure definition. + */ +struct _extint_module +{ +# if EXTINT_CALLBACK_MODE == true + /** Asynchronous channel callback table, for user-registered handlers */ + extint_callback_t callbacks[EIC_NUMBER_OF_INTERRUPTS]; +# else + /** Dummy value to ensure the struct has at least one member */ + uint8_t _dummy; +# endif +}; + +/** + * \brief Retrieves the base EIC module address from a given channel number. + * + * Retrieves the base address of a EIC hardware module associated with the + * given external interrupt channel. + * + * \param[in] channel External interrupt channel index to convert + * + * \return Base address of the associated EIC module. + */ +static inline Eic * _extint_get_eic_from_channel( + const uint8_t channel) +{ + uint8_t eic_index = (channel / 32); + + if (eic_index < EIC_INST_NUM) { + /* Array of available EICs */ + Eic *const eics[EIC_INST_NUM] = EIC_INSTS; + + return eics[eic_index]; + } else { + Assert(false); + return NULL; + } +} + +/** + * \brief Retrieves the base EIC module address from a given NMI channel number. + * + * Retrieves the base address of a EIC hardware module associated with the + * given non-maskable external interrupt channel. + * + * \param[in] nmi_channel Non-Maskable interrupt channel index to convert + * + * \return Base address of the associated EIC module. + */ +static inline Eic * _extint_get_eic_from_nmi( + const uint8_t nmi_channel) +{ + uint8_t eic_index = nmi_channel; + + if (eic_index < EIC_INST_NUM) { + /* Array of available EICs */ + Eic *const eics[EIC_INST_NUM] = EIC_INSTS; + + return eics[eic_index]; + } else { + Assert(false); + return NULL; + } +} +#endif + +/** \name Event Management + * @{ + */ + +void extint_enable_events( + struct extint_events *const events); + +void extint_disable_events( + struct extint_events *const events); + +/** @} */ + +/** \name Configuration and Initialization (Channel) + * @{ + */ + +void extint_chan_get_config_defaults( + struct extint_chan_conf *const config); + +void extint_chan_set_config( + const uint8_t channel, + const struct extint_chan_conf *const config); + +/** @} */ + +/** \name Configuration and Initialization (NMI) + * @{ + */ + +/** + * \brief Initializes an External Interrupt NMI channel configuration structure to defaults. + * + * Initializes a given External Interrupt NMI channel configuration structure + * to a set of known default values. This function should be called on all new + * instances of these configuration structures before being modified by the + * user application. + * + * The default configuration is as follows: + * \li Input filtering disabled + * \li Detect falling edges of a signal + * \li Asynchronous edge detection is disabled + * + * \param[out] config Configuration structure to initialize to default values + */ +static inline void extint_nmi_get_config_defaults( + struct extint_nmi_conf *const config) +{ + /* Sanity check arguments */ + Assert(config); + + /* Default configuration values */ + config->gpio_pin = 0; + config->gpio_pin_mux = 0; + config->gpio_pin_pull = EXTINT_PULL_UP; + config->filter_input_signal = false; + config->detection_criteria = EXTINT_DETECT_FALLING; +#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + config->enable_async_edge_detection = false; +#endif + +} + +enum status_code extint_nmi_set_config( + const uint8_t nmi_channel, + const struct extint_nmi_conf *const config); + +/** @} */ + +/** \name Detection testing and clearing (channel) + * @{ + */ + +/** + * \brief Retrieves the edge detection state of a configured channel. + * + * Reads the current state of a configured channel, and determines + * if the detection criteria of the channel has been met. + * + * \param[in] channel External Interrupt channel index to check + * + * \return Status of the requested channel's edge detection state. + * \retval true If the channel's edge/level detection criteria was met + * \retval false If the channel has not detected its configured criteria + */ +static inline bool extint_chan_is_detected( + const uint8_t channel) +{ + Eic *const eic_module = _extint_get_eic_from_channel(channel); + uint32_t eic_mask = (1UL << (channel % 32)); + + return (eic_module->INTFLAG.reg & eic_mask); +} + +/** + * \brief Clears the edge detection state of a configured channel. + * + * Clears the current state of a configured channel, readying it for + * the next level or edge detection. + * + * \param[in] channel External Interrupt channel index to check + */ +static inline void extint_chan_clear_detected( + const uint8_t channel) +{ + Eic *const eic_module = _extint_get_eic_from_channel(channel); + uint32_t eic_mask = (1UL << (channel % 32)); + + eic_module->INTFLAG.reg = eic_mask; +} + +/** @} */ + +/** \name Detection Testing and Clearing (NMI) + * @{ + */ + +/** + * \brief Retrieves the edge detection state of a configured NMI channel. + * + * Reads the current state of a configured NMI channel, and determines + * if the detection criteria of the NMI channel has been met. + * + * \param[in] nmi_channel External Interrupt NMI channel index to check + * + * \return Status of the requested NMI channel's edge detection state. + * \retval true If the NMI channel's edge/level detection criteria was met + * \retval false If the NMI channel has not detected its configured criteria + */ +static inline bool extint_nmi_is_detected( + const uint8_t nmi_channel) +{ + Eic *const eic_module = _extint_get_eic_from_nmi(nmi_channel); + + return (eic_module->NMIFLAG.reg & EIC_NMIFLAG_NMI); +} + +/** + * \brief Clears the edge detection state of a configured NMI channel. + * + * Clears the current state of a configured NMI channel, readying it for + * the next level or edge detection. + * + * \param[in] nmi_channel External Interrupt NMI channel index to check + */ +static inline void extint_nmi_clear_detected( + const uint8_t nmi_channel) +{ + Eic *const eic_module = _extint_get_eic_from_nmi(nmi_channel); + + eic_module->NMIFLAG.reg = EIC_NMIFLAG_NMI; +} + +/** @} */ + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#if EXTINT_CALLBACK_MODE == true +# include "extint_callback.h" +#endif + +/** + * \page asfdoc_sam0_extint_extra Extra Information for EXTINT Driver + * + * \section asfdoc_sam0_extint_extra_acronyms Acronyms + * The table below presents the acronyms used in this module: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
AcronymDescription
EICExternal Interrupt Controller
MUXMultiplexer
NMINon-Maskable Interrupt
+ * + * + * \section asfdoc_sam0_extint_extra_dependencies Dependencies + * This driver has the following dependencies: + * + * - \ref asfdoc_sam0_system_pinmux_group "System Pin Multiplexer Driver" + * + * + * \section asfdoc_sam0_extint_extra_errata Errata + * There are no errata related to this driver. + * + * + * \section asfdoc_sam0_extint_extra_history Module History + * An overview of the module history is presented in the table below, with + * details on the enhancements and fixes made to the module since its first + * release. The current version of this corresponds to the newest version in + * the table. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Changelog
+ * \li Driver updated to follow driver type convention + * \li Removed \c %extint_reset(), \c %extint_disable() and + * \c extint_enable() functions. Added internal function + * \c %_system_extint_init(). + * \li Added configuration EXTINT_CLOCK_SOURCE in conf_extint.h + * \li Removed configuration EXTINT_CALLBACKS_MAX in conf_extint.h, and + * added channel parameter in the register functions + * \c %extint_register_callback() and \c %extint_unregister_callback() + *
Updated interrupt handler to clear interrupt flag before calling + * callback function
Updated initialization function to also enable the digital interface + * clock to the module if it is disabled
Initial Release
+ */ + +/** + * \page asfdoc_sam0_extint_exqsg Examples for EXTINT Driver + * + * This is a list of the available Quick Start guides (QSGs) and example + * applications for \ref asfdoc_sam0_extint_group. + * QSGs are simple examples with step-by-step instructions to configure and + * use this driver in a selection of use cases. Note that a QSG can be compiled + * as a standalone application or be added to the user application. + * + * - \subpage asfdoc_sam0_extint_basic_use_case + * \if EXTINT_CALLBACK_MODE + * - \subpage asfdoc_sam0_extint_callback_use_case + * \endif + * + * \page asfdoc_sam0_extint_document_revision_history Document Revision History + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Doc. Rev.DateComments
42112E12/2015Added support for SAM L21/L22, SAM C21, SAM D09, and SAM DA1
42112D12/2014Added support for SAM R21 and SAM D10/D11
42112C01/2014Added support for SAM D21
42112B06/2013Added additional documentation on the event system. Corrected + * documentation typos.
42112A06/2013Initial release
+ */ + +#endif diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/extint/extint_callback.c b/src/boards/mcu/samr34/ASF/sam0/drivers/extint/extint_callback.c new file mode 100644 index 000000000..4cf0dbf0b --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/extint/extint_callback.c @@ -0,0 +1,222 @@ +/** + * \file + * + * \brief SAM External Interrupt Driver + * + * Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#include "extint.h" +#include "extint_callback.h" + +/** + * \internal + * Internal driver device instance struct, declared in the main module driver. + */ +extern struct _extint_module _extint_dev; + +/** + * \internal + * This is the number of the channel whose callback is currently running. + */ +uint8_t _current_channel; + +/** + * \brief Registers an asynchronous callback function with the driver. + * + * Registers an asynchronous callback with the EXTINT driver, fired when a + * channel detects the configured channel detection criteria + * (e.g. edge or level). Callbacks are fired once for each detected channel. + * + * \note NMI channel callbacks cannot be registered via this function; the + * device's NMI interrupt should be hooked directly in the user + * application and the NMI flags manually cleared via + * \ref extint_nmi_clear_detected(). + * + * \param[in] callback Pointer to the callback function to register + * \param[in] channel Logical channel to register callback for + * \param[in] type Type of callback function to register + * + * \return Status of the registration operation. + * \retval STATUS_OK The callback was registered successfully + * \retval STATUS_ERR_INVALID_ARG If an invalid callback type was supplied + * \retval STATUS_ERR_ALREADY_INITIALIZED Callback function has been + * registered, need unregister first + */ +enum status_code extint_register_callback( + const extint_callback_t callback, + const uint8_t channel, + const enum extint_callback_type type) +{ + /* Sanity check arguments */ + Assert(callback); + + if (type != EXTINT_CALLBACK_TYPE_DETECT) { + Assert(false); + return STATUS_ERR_INVALID_ARG; + } + + if (_extint_dev.callbacks[channel] == NULL) { + _extint_dev.callbacks[channel] = callback; + return STATUS_OK; + } else if (_extint_dev.callbacks[channel] == callback) { + return STATUS_OK; + } + + return STATUS_ERR_ALREADY_INITIALIZED; +} + +/** + * \brief Unregisters an asynchronous callback function with the driver. + * + * Unregisters an asynchronous callback with the EXTINT driver, removing it + * from the internal callback registration table. + * + * \param[in] callback Pointer to the callback function to unregister + * \param[in] channel Logical channel to unregister callback for + * \param[in] type Type of callback function to unregister + * + * \return Status of the de-registration operation. + * \retval STATUS_OK The callback was unregistered successfully + * \retval STATUS_ERR_INVALID_ARG If an invalid callback type was supplied + * \retval STATUS_ERR_BAD_ADDRESS No matching entry was found in the + * registration table + */ +enum status_code extint_unregister_callback( + const extint_callback_t callback, + const uint8_t channel, + const enum extint_callback_type type) +{ + /* Sanity check arguments */ + Assert(callback); + + if (type != EXTINT_CALLBACK_TYPE_DETECT) { + Assert(false); + return STATUS_ERR_INVALID_ARG; + } + + if (_extint_dev.callbacks[channel] == callback) { + _extint_dev.callbacks[channel] = NULL; + return STATUS_OK; + } + + return STATUS_ERR_BAD_ADDRESS; +} + +/** + * \brief Enables asynchronous callback generation for a given channel and type. + * + * Enables asynchronous callbacks for a given logical external interrupt channel + * and type. This must be called before an external interrupt channel will + * generate callback events. + * + * \param[in] channel Logical channel to enable callback generation for + * \param[in] type Type of callback function callbacks to enable + * + * \return Status of the callback enable operation. + * \retval STATUS_OK The callback was enabled successfully + * \retval STATUS_ERR_INVALID_ARG If an invalid callback type was supplied + */ +enum status_code extint_chan_enable_callback( + const uint8_t channel, + const enum extint_callback_type type) +{ + if (type == EXTINT_CALLBACK_TYPE_DETECT) { + Eic *const eic = _extint_get_eic_from_channel(channel); + + eic->INTENSET.reg = (1UL << channel); + } + else { + Assert(false); + return STATUS_ERR_INVALID_ARG; + } + + return STATUS_OK; +} + +/** + * \brief Disables asynchronous callback generation for a given channel and type. + * + * Disables asynchronous callbacks for a given logical external interrupt + * channel and type. + * + * \param[in] channel Logical channel to disable callback generation for + * \param[in] type Type of callback function callbacks to disable + * + * \return Status of the callback disable operation. + * \retval STATUS_OK The callback was disabled successfully + * \retval STATUS_ERR_INVALID_ARG If an invalid callback type was supplied + */ +enum status_code extint_chan_disable_callback( + const uint8_t channel, + const enum extint_callback_type type) +{ + if (type == EXTINT_CALLBACK_TYPE_DETECT) { + Eic *const eic = _extint_get_eic_from_channel(channel); + + eic->INTENCLR.reg = (1UL << channel); + } + else { + Assert(false); + return STATUS_ERR_INVALID_ARG; + } + + return STATUS_OK; +} + +/** + * \brief Find what channel caused the callback. + * + * Can be used in an EXTINT callback function to find what channel caused + * the callback in case the same callback is used by multiple channels. + * + * \return Channel number. + */ +uint8_t extint_get_current_channel(void) +{ + return _current_channel; +} + +/** Handler for the EXTINT hardware module interrupt. */ +void EIC_Handler(void) +{ + /* Find any triggered channels, run associated callback handlers */ + for (_current_channel = 0; _current_channel < EIC_NUMBER_OF_INTERRUPTS ; _current_channel++) { + if (extint_chan_is_detected(_current_channel)) { + /* Clear flag */ + extint_chan_clear_detected(_current_channel); + /* Find any associated callback entries in the callback table */ + if (_extint_dev.callbacks[_current_channel] != NULL) { + /* Run the registered callback */ + _extint_dev.callbacks[_current_channel](); + } + } + } +} diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/extint/extint_callback.h b/src/boards/mcu/samr34/ASF/sam0/drivers/extint/extint_callback.h new file mode 100644 index 000000000..68ee7c7f9 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/extint/extint_callback.h @@ -0,0 +1,98 @@ +/** + * \file + * + * \brief SAM External Interrupt Driver + * + * Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#ifndef EXTINT_CALLBACK_H_INCLUDED +#define EXTINT_CALLBACK_H_INCLUDED + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup asfdoc_sam0_extint_group + * + * @{ + */ + +/** \name Callback Configuration and Initialization + * @{ + */ + +/** Enum for the possible callback types for the EXTINT module. */ +enum extint_callback_type +{ + /** Callback type for when an external interrupt detects the configured + * channel criteria (i.e. edge or level detection) + */ + EXTINT_CALLBACK_TYPE_DETECT, +}; + +enum status_code extint_register_callback( + const extint_callback_t callback, + const uint8_t channel, + const enum extint_callback_type type); + +enum status_code extint_unregister_callback( + const extint_callback_t callback, + const uint8_t channel, + const enum extint_callback_type type); + +uint8_t extint_get_current_channel(void); + +/** @} */ + +/** \name Callback Enabling and Disabling (Channel) + * @{ + */ + +enum status_code extint_chan_enable_callback( + const uint8_t channel, + const enum extint_callback_type type); + +enum status_code extint_chan_disable_callback( + const uint8_t channel, + const enum extint_callback_type type); + +/** @} */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/extint/extint_sam_l_c/extint.c b/src/boards/mcu/samr34/ASF/sam0/drivers/extint/extint_sam_l_c/extint.c new file mode 100644 index 000000000..a469f0179 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/extint/extint_sam_l_c/extint.c @@ -0,0 +1,481 @@ +/** + * \file + * + * \brief SAM External Interrupt Driver + * + * Copyright (c) 2014-2020 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#include +#include +#include +#include + +#if !defined(EXTINT_CLOCK_SELECTION) || defined(__DOXYGEN__) +# warning EXTINT_CLOCK_SELECTION is not defined, assuming EXTINT_CLK_GCLK. + +/** Configuration option, setting the EIC clock source which can be used for + * EIC edge detection or filtering. This option may be overridden in the module + * configuration header file \c conf_extint.h. + */ +# define EXTINT_CLOCK_SELECTION EXTINT_CLK_GCLK +#endif + +#if (EXTINT_CLOCK_SELECTION == EXTINT_CLK_GCLK) +#if !defined(EXTINT_CLOCK_SOURCE) || defined(__DOXYGEN__) +# warning EXTINT_CLOCK_SOURCE is not defined, assuming GCLK_GENERATOR_0. + +/** Configuration option, setting the EIC clock source which can be used for + * EIC edge detection or filtering. This option may be overridden in the module + * configuration header file \c conf_extint.h. + */ +# define EXTINT_CLOCK_SOURCE GCLK_GENERATOR_0 +#endif +#endif + +/** + * \internal + * Internal driver device instance struct. + */ +struct _extint_module _extint_dev; + +/** + * \brief Determin if the general clock is required. + * + * \param[in] filter_input_signal Filter the raw input signal to prevent noise + * \param[in] detection_criteria Edge detection mode to use (\ref extint_detect) + */ +#define _extint_is_gclk_required(filter_input_signal, detection_criteria) \ + ((filter_input_signal) ? true : (\ + (EXTINT_DETECT_RISING == (detection_criteria)) ? true : (\ + (EXTINT_DETECT_FALLING == (detection_criteria)) ? true : (\ + (EXTINT_DETECT_BOTH == (detection_criteria)) ? true : false)))) + +static void _extint_enable(void); +static void _extint_disable(void); + +/** + * \brief Determines if the hardware module(s) are currently synchronizing to the bus. + * + * Checks to see if the underlying hardware peripheral module(s) are currently + * synchronizing across multiple clock domains to the hardware bus, This + * function can be used to delay further operations on a module until such time + * that it is ready, to prevent blocking delays for synchronization in the + * user application. + * + * \return Synchronization status of the underlying hardware module(s). + * + * \retval true If the module synchronization is ongoing + * \retval false If the module has completed synchronization + */ +static inline bool extint_is_syncing(void) +{ + Eic *const eics[EIC_INST_NUM] = EIC_INSTS; + + for (uint32_t i = 0; i < EIC_INST_NUM; i++) { + if((eics[i]->SYNCBUSY.reg & EIC_SYNCBUSY_ENABLE) + || (eics[i]->SYNCBUSY.reg & EIC_SYNCBUSY_SWRST)){ + return true; + } + } + return false; +} + +/** + * \internal + * \brief Initializes and enables the External Interrupt driver. + * + * Enable the clocks used by External Interrupt driver. + * + * Resets the External Interrupt driver, resetting all hardware + * module registers to their power-on defaults, then enable it for further use. + * + * Reset the callback list if callback mode is used. + * + * This function must be called before attempting to use any NMI or standard + * external interrupt channel functions. + * + * \note When SYSTEM module is used, this function will be invoked by + * \ref system_init() automatically if the module is included. + */ +void _system_extint_init(void); +void _system_extint_init(void) +{ + Eic *const eics[EIC_INST_NUM] = EIC_INSTS; + + /* Turn on the digital interface clock */ + system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBA, MCLK_APBAMASK_EIC); + +#if (EXTINT_CLOCK_SELECTION == EXTINT_CLK_GCLK) + /* Configure the generic clock for the module and enable it */ + struct system_gclk_chan_config gclk_chan_conf; + system_gclk_chan_get_config_defaults(&gclk_chan_conf); + gclk_chan_conf.source_generator = EXTINT_CLOCK_SOURCE; + system_gclk_chan_set_config(EIC_GCLK_ID, &gclk_chan_conf); + + /* Enable the clock anyway, since when needed it will be requested + * by External Interrupt driver */ + system_gclk_chan_enable(EIC_GCLK_ID); +#endif + + /* Reset all EIC hardware modules. */ + for (uint32_t i = 0; i < EIC_INST_NUM; i++) { + eics[i]->CTRLA.reg |= EIC_CTRLA_SWRST; + } + + while (extint_is_syncing()) { + /* Wait for all hardware modules to complete synchronization */ + } + +#if (EXTINT_CLOCK_SELECTION == EXTINT_CLK_GCLK) + for (uint32_t i = 0; i < EIC_INST_NUM; i++) { + eics[i]->CTRLA.bit.CKSEL = EXTINT_CLK_GCLK; + } +#else + for (uint32_t i = 0; i < EIC_INST_NUM; i++) { + eics[i]->CTRLA.bit.CKSEL = EXTINT_CLK_ULP32K; + } +#endif + + /* Reset the software module */ +#if EXTINT_CALLBACK_MODE == true + /* Clear callback registration table */ + for (uint8_t j = 0; j < EIC_NUMBER_OF_INTERRUPTS; j++) { + _extint_dev.callbacks[j] = NULL; + } + system_interrupt_enable(SYSTEM_INTERRUPT_MODULE_EIC); +#endif + + /* Enables the driver for further use */ + _extint_enable(); +} + +/** + * \internal + * \brief Enables the External Interrupt driver. + * + * Enables EIC modules. + * Registered callback list will not be affected if callback mode is used. + */ +void _extint_enable(void) +{ + Eic *const eics[EIC_INST_NUM] = EIC_INSTS; + + /* Enable all EIC hardware modules. */ + for (uint32_t i = 0; i < EIC_INST_NUM; i++) { + eics[i]->CTRLA.reg |= EIC_CTRLA_ENABLE; + } + + while (extint_is_syncing()) { + /* Wait for all hardware modules to complete synchronization */ + } +} + +/** + * \internal + * \brief Disables the External Interrupt driver. + * + * Disables EIC modules that were previously started via a call to + * \ref _extint_enable(). + * Registered callback list will not be affected if callback mode is used. + */ +void _extint_disable(void) +{ + Eic *const eics[EIC_INST_NUM] = EIC_INSTS; + + /* Disable all EIC hardware modules. */ + for (uint32_t i = 0; i < EIC_INST_NUM; i++) { + eics[i]->CTRLA.reg &= ~EIC_CTRLA_ENABLE; + } + + while (extint_is_syncing()) { + /* Wait for all hardware modules to complete synchronization */ + } +} + +/** + * \brief Initializes an External Interrupt channel configuration structure to defaults. + * + * Initializes a given External Interrupt channel configuration structure to a + * set of known default values. This function should be called on all new + * instances of these configuration structures before being modified by the + * user application. + * + * The default configuration is as follows: + * \li Input filtering disabled + * \li Internal pull-up enabled + * \li Detect falling edges of a signal + * \li Asynchronous edge detection is disabled + * + * \param[out] config Configuration structure to initialize to default values + */ +void extint_chan_get_config_defaults( + struct extint_chan_conf *const config) +{ + /* Sanity check arguments */ + Assert(config); + + /* Default configuration values */ + config->gpio_pin = 0; + config->gpio_pin_mux = 0; + config->gpio_pin_pull = EXTINT_PULL_UP; + config->filter_input_signal = false; + config->detection_criteria = EXTINT_DETECT_FALLING; + config->enable_async_edge_detection = false; +} + +/** + * \brief Writes an External Interrupt channel configuration to the hardware module. + * + * Writes out a given configuration of an External Interrupt channel + * configuration to the hardware module. If the channel is already configured, + * the new configuration will replace the existing one. + * + * \param[in] channel External Interrupt channel to configure + * \param[in] config Configuration settings for the channel + + */ +void extint_chan_set_config( + const uint8_t channel, + const struct extint_chan_conf *const config) +{ + /* Sanity check arguments */ + Assert(config); + _extint_disable(); +#if(EXTINT_CLOCK_SELECTION == EXTINT_CLK_GCLK) + /* Sanity check clock requirements */ + Assert(!(!system_gclk_gen_is_enabled(EXTINT_CLOCK_SOURCE) && + _extint_is_gclk_required(config->filter_input_signal, + config->detection_criteria))); +#endif + struct system_pinmux_config pinmux_config; + system_pinmux_get_config_defaults(&pinmux_config); + + pinmux_config.mux_position = config->gpio_pin_mux; + pinmux_config.direction = SYSTEM_PINMUX_PIN_DIR_INPUT; + pinmux_config.input_pull = (enum system_pinmux_pin_pull)config->gpio_pin_pull; + system_pinmux_pin_set_config(config->gpio_pin, &pinmux_config); + + /* Get a pointer to the module hardware instance */ + Eic *const EIC_module = _extint_get_eic_from_channel(channel); + + uint32_t config_pos = (4 * (channel % 8)); + uint32_t new_config; + + /* Determine the channel's new edge detection configuration */ + new_config = (config->detection_criteria << EIC_CONFIG_SENSE0_Pos); + + /* Enable the hardware signal filter if requested in the config */ + if (config->filter_input_signal) { + new_config |= EIC_CONFIG_FILTEN0; + } + + /* Clear the existing and set the new channel configuration */ + EIC_module->CONFIG[channel / 8].reg + = (EIC_module->CONFIG[channel / 8].reg & + ~((EIC_CONFIG_SENSE0_Msk | EIC_CONFIG_FILTEN0) << config_pos)) | + (new_config << config_pos); +#if (SAML22) || (SAML21XXXB) || (SAMC20) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + /* Config asynchronous edge detection */ + if (config->enable_async_edge_detection) { + EIC_module->ASYNCH.reg |= (1UL << channel); + } else { + EIC_module->ASYNCH.reg &= (EIC_ASYNCH_MASK & (~(1UL << channel))); + } +#endif +#if (SAMC21) + /* Config asynchronous edge detection */ + if (config->enable_async_edge_detection) { + EIC_module->EIC_ASYNCH.reg |= (1UL << channel); + } else { + EIC_module->EIC_ASYNCH.reg &= (EIC_EIC_ASYNCH_MASK & (~(1UL << channel))); + } +#endif + _extint_enable(); +} + +/** + * \brief Writes an External Interrupt NMI channel configuration to the hardware module. + * + * Writes out a given configuration of an External Interrupt NMI channel + * configuration to the hardware module. If the channel is already configured, + * the new configuration will replace the existing one. + * + * \param[in] nmi_channel External Interrupt NMI channel to configure + * \param[in] config Configuration settings for the channel + * + * \returns Status code indicating the success or failure of the request. + * \retval STATUS_OK Configuration succeeded + * \retval STATUS_ERR_PIN_MUX_INVALID An invalid pin mux value was supplied + * \retval STATUS_ERR_BAD_FORMAT An invalid detection mode was requested + */ +enum status_code extint_nmi_set_config( + const uint8_t nmi_channel, + const struct extint_nmi_conf *const config) +{ + /* Sanity check arguments */ + Assert(config); + + /* Sanity check clock requirements */ + Assert(!(!system_gclk_gen_is_enabled(EXTINT_CLOCK_SOURCE) && + _extint_is_gclk_required(config->filter_input_signal, + config->detection_criteria))); + + struct system_pinmux_config pinmux_config; + system_pinmux_get_config_defaults(&pinmux_config); + + pinmux_config.mux_position = config->gpio_pin_mux; + pinmux_config.direction = SYSTEM_PINMUX_PIN_DIR_INPUT; + pinmux_config.input_pull = SYSTEM_PINMUX_PIN_PULL_UP; + pinmux_config.input_pull = (enum system_pinmux_pin_pull)config->gpio_pin_pull; + system_pinmux_pin_set_config(config->gpio_pin, &pinmux_config); + + /* Get a pointer to the module hardware instance */ + Eic *const EIC_module = _extint_get_eic_from_channel(nmi_channel); + + uint32_t new_config; + + /* Determine the NMI's new edge detection configuration */ + new_config = (config->detection_criteria << EIC_NMICTRL_NMISENSE_Pos); + + /* Enable the hardware signal filter if requested in the config */ + if (config->filter_input_signal) { + new_config |= EIC_NMICTRL_NMIFILTEN; + } + +#if (SAML21XXXB) || (SAML22) || (SAMC21) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + /* Enable asynchronous edge detection if requested in the config */ + if (config->enable_async_edge_detection) { + new_config |= EIC_NMICTRL_NMIASYNCH; + } +#endif + + /* Disable EIC and general clock to configure NMI */ + _extint_disable(); +#if(EXTINT_CLOCK_SELECTION == EXTINT_CLK_GCLK) + system_gclk_chan_disable(EIC_GCLK_ID); +#else + Eic *const eics[EIC_INST_NUM] = EIC_INSTS; + for (uint32_t i = 0; i < EIC_INST_NUM; i++){ + eics[i]->CTRLA.bit.CKSEL = EXTINT_CLK_GCLK; + system_gclk_chan_disable(EIC_GCLK_ID); + } +#endif + + EIC_module->NMICTRL.reg = new_config; + + /* Enable the EIC clock and EIC after configure NMI */ +#if(EXTINT_CLOCK_SELECTION == EXTINT_CLK_GCLK) + system_gclk_chan_enable(EIC_GCLK_ID); +#else + for (uint32_t i = 0; i < EIC_INST_NUM; i++){ + eics[i]->CTRLA.bit.CKSEL = EXTINT_CLK_ULP32K; + } +#endif + _extint_enable(); + + return STATUS_OK; +} + +/** + * \brief Enables an External Interrupt event output. + * + * Enables one or more output events from the External Interrupt module. See + * \ref extint_events "here" for a list of events this module supports. + * + * \note Events cannot be altered while the module is enabled. + * + * \param[in] events Struct containing flags of events to enable + */ +void extint_enable_events( + struct extint_events *const events) +{ + /* Sanity check arguments */ + Assert(events); + + /* Array of available EICs. */ + Eic *const eics[EIC_INST_NUM] = EIC_INSTS; + + _extint_disable(); + + /* Update the event control register for each physical EIC instance */ + for (uint32_t i = 0; i < EIC_INST_NUM; i++) { + uint32_t event_mask = 0; + + /* Create an enable mask for the current EIC module */ + for (uint32_t j = 0; j < 32; j++) { + if (events->generate_event_on_detect[(32 * i) + j]) { + event_mask |= (1UL << j); + } + } + + /* Enable the masked events */ + eics[i]->EVCTRL.reg |= event_mask; + } + _extint_enable(); +} + +/** + * \brief Disables an External Interrupt event output. + * + * Disables one or more output events from the External Interrupt module. See + * \ref extint_events "here" for a list of events this module supports. + * + * \note Events cannot be altered while the module is enabled. + * + * \param[in] events Struct containing flags of events to disable + */ +void extint_disable_events( + struct extint_events *const events) +{ + /* Sanity check arguments */ + Assert(events); + + /* Array of available EICs. */ + Eic *const eics[EIC_INST_NUM] = EIC_INSTS; + + _extint_disable(); + + /* Update the event control register for each physical EIC instance */ + for (uint32_t i = 0; i < EIC_INST_NUM; i++) { + uint32_t event_mask = 0; + + /* Create a disable mask for the current EIC module */ + for (uint32_t j = 0; j < 32; j++) { + if (events->generate_event_on_detect[(32 * i) + j]) { + event_mask |= (1UL << j); + } + } + + /* Disable the masked events */ + eics[i]->EVCTRL.reg &= ~event_mask; + } + _extint_enable(); +} diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/nvm/nvm.c b/src/boards/mcu/samr34/ASF/sam0/drivers/nvm/nvm.c new file mode 100644 index 000000000..a6bd9332c --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/nvm/nvm.c @@ -0,0 +1,1139 @@ +/** + * \file + * + * \brief SAM Non Volatile Memory driver + * + * Copyright (c) 2012-2020 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#include "nvm.h" +#include +#include +#include + +/** + * \internal Internal device instance struct + * + * This struct contains information about the NVM module which is + * often used by the different functions. The information is loaded + * into the struct in the nvm_init() function. + */ +struct _nvm_module { + /** Number of bytes contained per page. */ + uint16_t page_size; + /** Total number of pages in the NVM memory. */ + uint16_t number_of_pages; + /** If \c false, a page write command will be issued automatically when the + * page buffer is full. */ + bool manual_page_write; +}; + +/** + * \internal Instance of the internal device struct + */ +static struct _nvm_module _nvm_dev; + +/** + * \internal Pointer to the NVM MEMORY region start address + */ +#define NVM_MEMORY ((volatile uint16_t *)FLASH_ADDR) + +/** + * \internal Pointer to the NVM USER MEMORY region start address + */ +#define NVM_USER_MEMORY ((volatile uint16_t *)NVMCTRL_USER) + + +/** + * \brief Sets the up the NVM hardware module based on the configuration. + * + * Writes a given configuration of an NVM controller configuration to the + * hardware module, and initializes the internal device struct. + * + * \param[in] config Configuration settings for the NVM controller + * + * \note The security bit must be cleared in order successfully use this + * function. This can only be done by a chip erase. + * + * \return Status of the configuration procedure. + * + * \retval STATUS_OK If the initialization was a success + * \retval STATUS_BUSY If the module was busy when the operation was attempted + * \retval STATUS_ERR_IO If the security bit has been set, preventing the + * EEPROM and/or auxiliary space configuration from being + * altered + */ +enum status_code nvm_set_config( + const struct nvm_config *const config) +{ + /* Sanity check argument */ + Assert(config); + + /* Get a pointer to the module hardware instance */ + Nvmctrl *const nvm_module = NVMCTRL; + +#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + /* Turn on the digital interface clock */ + system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBB, MCLK_APBBMASK_NVMCTRL); +#else + /* Turn on the digital interface clock */ + system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBB, PM_APBBMASK_NVMCTRL); +#endif + + /* Clear error flags */ + nvm_module->STATUS.reg = NVMCTRL_STATUS_MASK; + + /* Check if the module is busy */ + if (!nvm_is_ready()) { + return STATUS_BUSY; + } + +#if (!SAMC20) && (!SAMC21) + /* Writing configuration to the CTRLB register */ + nvm_module->CTRLB.reg = + NVMCTRL_CTRLB_SLEEPPRM(config->sleep_power_mode) | + ((config->manual_page_write & 0x01) << NVMCTRL_CTRLB_MANW_Pos) | + NVMCTRL_CTRLB_RWS(config->wait_states) | + ((config->disable_cache & 0x01) << NVMCTRL_CTRLB_CACHEDIS_Pos) | + NVMCTRL_CTRLB_READMODE(config->cache_readmode); +#else + uint8_t cache_disable_value = 0; + if (config->disable_rww_cache == false) { + cache_disable_value = 0x02; + } else { + cache_disable_value = (config->disable_cache & 0x01); + } + /* Writing configuration to the CTRLB register */ + nvm_module->CTRLB.reg = + NVMCTRL_CTRLB_SLEEPPRM(config->sleep_power_mode) | + ((config->manual_page_write & 0x01) << NVMCTRL_CTRLB_MANW_Pos) | + NVMCTRL_CTRLB_RWS(config->wait_states) | + (cache_disable_value << NVMCTRL_CTRLB_CACHEDIS_Pos) | + NVMCTRL_CTRLB_READMODE(config->cache_readmode); +#endif + + /* Initialize the internal device struct */ + _nvm_dev.page_size = (8 << nvm_module->PARAM.bit.PSZ); + _nvm_dev.number_of_pages = nvm_module->PARAM.bit.NVMP; + _nvm_dev.manual_page_write = config->manual_page_write; + + /* If the security bit is set, the auxiliary space cannot be written */ + if (nvm_module->STATUS.reg & NVMCTRL_STATUS_SB) { + return STATUS_ERR_IO; + } + + return STATUS_OK; +} + +/** + * \brief Executes a command on the NVM controller. + * + * Executes an asynchronous command on the NVM controller, to perform a requested + * action such as an NVM page read or write operation. + * + * \note The function will return before the execution of the given command is + * completed. + * + * \param[in] command Command to issue to the NVM controller + * \param[in] address Address to pass to the NVM controller in NVM memory + * space + * \param[in] parameter Parameter to pass to the NVM controller, not used + * for this driver + * + * \return Status of the attempt to execute a command. + * + * \retval STATUS_OK If the command was accepted and execution + * is now in progress + * \retval STATUS_BUSY If the NVM controller was already busy + * executing a command when the new command + * was issued + * \retval STATUS_ERR_IO If the command was invalid due to memory or + * security locking + * \retval STATUS_ERR_INVALID_ARG If the given command was invalid or + * unsupported + * \retval STATUS_ERR_BAD_ADDRESS If the given address was invalid + */ +enum status_code nvm_execute_command( + const enum nvm_command command, + const uint32_t address, + const uint32_t parameter) +{ + uint32_t ctrlb_bak; + + /* Check that the address given is valid */ + if (address > ((uint32_t)_nvm_dev.page_size * _nvm_dev.number_of_pages) + && !(address >= NVMCTRL_AUX0_ADDRESS && address <= NVMCTRL_AUX1_ADDRESS )){ +#ifdef FEATURE_NVM_RWWEE + if (address >= ((uint32_t)NVMCTRL_RWW_EEPROM_SIZE + NVMCTRL_RWW_EEPROM_ADDR) + || address < NVMCTRL_RWW_EEPROM_ADDR){ + return STATUS_ERR_BAD_ADDRESS; + } +#else + return STATUS_ERR_BAD_ADDRESS; +#endif + } + + /* Get a pointer to the module hardware instance */ + Nvmctrl *const nvm_module = NVMCTRL; + + /* Turn off cache before issuing flash commands */ + ctrlb_bak = nvm_module->CTRLB.reg; +#if (SAMC20) || (SAMC21) + nvm_module->CTRLB.reg = ((ctrlb_bak &(~(NVMCTRL_CTRLB_CACHEDIS(0x2)))) + | NVMCTRL_CTRLB_CACHEDIS(0x1)); +#else + nvm_module->CTRLB.reg = ctrlb_bak | NVMCTRL_CTRLB_CACHEDIS; +#endif + + /* Clear error flags */ + nvm_module->STATUS.reg = NVMCTRL_STATUS_MASK; + + /* Check if the module is busy */ + if (!nvm_is_ready()) { + /* Restore the setting */ + nvm_module->CTRLB.reg = ctrlb_bak; + return STATUS_BUSY; + } + + switch (command) { + + /* Commands requiring address (protected) */ + case NVM_COMMAND_ERASE_AUX_ROW: + case NVM_COMMAND_WRITE_AUX_ROW: + + /* Auxiliary space cannot be accessed if the security bit is set */ + if (nvm_module->STATUS.reg & NVMCTRL_STATUS_SB) { + /* Restore the setting */ + nvm_module->CTRLB.reg = ctrlb_bak; + return STATUS_ERR_IO; + } + + /* Set address, command will be issued elsewhere */ + nvm_module->ADDR.reg = (uintptr_t)&NVM_MEMORY[address / 4]; + break; + + /* Commands requiring address (unprotected) */ + case NVM_COMMAND_ERASE_ROW: + case NVM_COMMAND_WRITE_PAGE: + case NVM_COMMAND_LOCK_REGION: + case NVM_COMMAND_UNLOCK_REGION: +#ifdef FEATURE_NVM_RWWEE + case NVM_COMMAND_RWWEE_ERASE_ROW: + case NVM_COMMAND_RWWEE_WRITE_PAGE: +#endif + + /* Set address, command will be issued elsewhere */ + nvm_module->ADDR.reg = (uintptr_t)&NVM_MEMORY[address / 4]; + break; + + /* Commands not requiring address */ + case NVM_COMMAND_PAGE_BUFFER_CLEAR: + case NVM_COMMAND_SET_SECURITY_BIT: + case NVM_COMMAND_ENTER_LOW_POWER_MODE: + case NVM_COMMAND_EXIT_LOW_POWER_MODE: + break; + + default: + /* Restore the setting */ + nvm_module->CTRLB.reg = ctrlb_bak; + return STATUS_ERR_INVALID_ARG; + } + + /* Disable Cache */ +#ifdef FEATURE_NVM_RWWEE + if( command == NVM_COMMAND_RWWEE_ERASE_ROW || command == NVM_COMMAND_RWWEE_WRITE_PAGE) + { + nvm_module->CTRLB.bit.CACHEDIS = 1; + nvm_module->CTRLB.reg; + } +#endif + + /* Set command */ + nvm_module->CTRLA.reg = command | NVMCTRL_CTRLA_CMDEX_KEY; + + /* Wait for the NVM controller to become ready */ + while (!nvm_is_ready()) { + } + + /* Enable Cache */ +#ifdef FEATURE_NVM_RWWEE + if( command == NVM_COMMAND_RWWEE_ERASE_ROW || command == NVM_COMMAND_RWWEE_WRITE_PAGE) + { + nvm_module->CTRLB.bit.CACHEDIS = 0; + } +#endif + + /* Restore the setting */ + nvm_module->CTRLB.reg = ctrlb_bak; + + return STATUS_OK; +} + +/** + * \brief Updates an arbitrary section of a page with new data. + * + * Writes from a buffer to a given page in the NVM memory, retaining any + * unmodified data already stored in the page. + * + * \note If manual write mode is enable, the write command must be executed after + * this function, otherwise the data will not write to NVM from page buffer. + * + * \warning This routine is unsafe if data integrity is critical; a system reset + * during the update process will result in up to one row of data being + * lost. If corruption must be avoided in all circumstances (including + * power loss or system reset) this function should not be used. + * + * \param[in] destination_address Destination page address to write to + * \param[in] buffer Pointer to buffer where the data to write is + * stored + * \param[in] offset Number of bytes to offset the data write in + * the page + * \param[in] length Number of bytes in the page to update + * + * \return Status of the attempt to update a page. + * + * \retval STATUS_OK Requested NVM memory page was successfully + * read + * \retval STATUS_BUSY NVM controller was busy when the operation + * was attempted + * \retval STATUS_ERR_BAD_ADDRESS The requested address was outside the + * acceptable range of the NVM memory region + * \retval STATUS_ERR_INVALID_ARG The supplied length and offset was invalid + */ +enum status_code nvm_update_buffer( + const uint32_t destination_address, + uint8_t *const buffer, + uint16_t offset, + uint16_t length) +{ + enum status_code error_code = STATUS_OK; + uint8_t row_buffer[NVMCTRL_ROW_PAGES][NVMCTRL_PAGE_SIZE]; + + /* Ensure the read does not overflow the page size */ + if ((offset + length) > _nvm_dev.page_size) { + return STATUS_ERR_INVALID_ARG; + } + + /* Calculate the starting row address of the page to update */ + uint32_t row_start_address = + destination_address & ~((_nvm_dev.page_size * NVMCTRL_ROW_PAGES) - 1); + + /* Read in the current row contents */ + for (uint32_t i = 0; i < NVMCTRL_ROW_PAGES; i++) { + do + { + error_code = nvm_read_buffer( + row_start_address + (i * _nvm_dev.page_size), + row_buffer[i], _nvm_dev.page_size); + } while (error_code == STATUS_BUSY); + + if (error_code != STATUS_OK) { + return error_code; + } + } + + /* Calculate the starting page in the row that is to be updated */ + uint8_t page_in_row = + (destination_address % (_nvm_dev.page_size * NVMCTRL_ROW_PAGES)) / + _nvm_dev.page_size; + + /* Update the specified bytes in the page buffer */ + for (uint32_t i = 0; i < length; i++) { + row_buffer[page_in_row][offset + i] = buffer[i]; + } + + system_interrupt_enter_critical_section(); + + /* Erase the row */ + do + { + error_code = nvm_erase_row(row_start_address); + } while (error_code == STATUS_BUSY); + + if (error_code != STATUS_OK) { + system_interrupt_leave_critical_section(); + return error_code; + } + + /* Write the updated row contents to the erased row */ + for (uint32_t i = 0; i < NVMCTRL_ROW_PAGES; i++) { + do + { + error_code = nvm_write_buffer( + row_start_address + (i * _nvm_dev.page_size), + row_buffer[i], _nvm_dev.page_size); + } while (error_code == STATUS_BUSY); + + if (error_code != STATUS_OK) { + system_interrupt_leave_critical_section(); + return error_code; + } + } + + system_interrupt_leave_critical_section(); + + return error_code; +} + +/** + * \brief Writes a number of bytes to a page in the NVM memory region. + * + * Writes from a buffer to a given page address in the NVM memory. + * + * \param[in] destination_address Destination page address to write to + * \param[in] buffer Pointer to buffer where the data to write is + * stored + * \param[in] length Number of bytes in the page to write + * + * \note If writing to a page that has previously been written to, the page's + * row should be erased (via \ref nvm_erase_row()) before attempting to + * write new data to the page. + * + * \note For SAM D21 RWW devices, see \c SAMD21_64K, command \c NVM_COMMAND_RWWEE_WRITE_PAGE + * must be executed before any other commands after writing a page, + * refer to errata 13588. + * + * \note If manual write mode is enabled, the write command must be executed after + * this function, otherwise the data will not write to NVM from page buffer. + * + * \return Status of the attempt to write a page. + * + * \retval STATUS_OK Requested NVM memory page was successfully + * read + * \retval STATUS_BUSY NVM controller was busy when the operation + * was attempted + * \retval STATUS_ERR_BAD_ADDRESS The requested address was outside the + * acceptable range of the NVM memory region or + * not aligned to the start of a page + * \retval STATUS_ERR_INVALID_ARG The supplied write length was invalid + */ +enum status_code nvm_write_buffer( + const uint32_t destination_address, + const uint8_t *buffer, + uint16_t length) +{ +#ifdef FEATURE_NVM_RWWEE + bool is_rww_eeprom = false; +#endif + + /* Check if the destination address is valid */ + if (destination_address > + ((uint32_t)_nvm_dev.page_size * _nvm_dev.number_of_pages)) { +#ifdef FEATURE_NVM_RWWEE + if (destination_address >= ((uint32_t)NVMCTRL_RWW_EEPROM_SIZE + NVMCTRL_RWW_EEPROM_ADDR) + || destination_address < NVMCTRL_RWW_EEPROM_ADDR){ + return STATUS_ERR_BAD_ADDRESS; + } + is_rww_eeprom = true; +#else + return STATUS_ERR_BAD_ADDRESS; +#endif + } + + /* Check if the write address not aligned to the start of a page */ + if (destination_address & (_nvm_dev.page_size - 1)) { + return STATUS_ERR_BAD_ADDRESS; + } + + /* Check if the write length is longer than an NVM page */ + if (length > _nvm_dev.page_size) { + return STATUS_ERR_INVALID_ARG; + } + + /* Get a pointer to the module hardware instance */ + Nvmctrl *const nvm_module = NVMCTRL; + + /* Check if the module is busy */ + if (!nvm_is_ready()) { + return STATUS_BUSY; + } + + /* Erase the page buffer before buffering new data */ + nvm_module->CTRLA.reg = NVM_COMMAND_PAGE_BUFFER_CLEAR | NVMCTRL_CTRLA_CMDEX_KEY; + + /* Check if the module is busy */ + while (!nvm_is_ready()) { + /* Force-wait for the buffer clear to complete */ + } + + /* Clear error flags */ + nvm_module->STATUS.reg = NVMCTRL_STATUS_MASK; + + uint32_t nvm_address = destination_address / 2; + + /* NVM _must_ be accessed as a series of 16-bit words, perform manual copy + * to ensure alignment */ + for (uint16_t i = 0; i < length; i += 2) { + uint16_t data; + + /* Copy first byte of the 16-bit chunk to the temporary buffer */ + data = buffer[i]; + + /* If we are not at the end of a write request with an odd byte count, + * store the next byte of data as well */ + if (i < (length - 1)) { + data |= (buffer[i + 1] << 8); + } + + /* Store next 16-bit chunk to the NVM memory space */ + NVM_MEMORY[nvm_address++] = data; + } + + /* If automatic page write mode is enable, then perform a manual NVM + * write when the length of data to be programmed is less than page size + */ + if ((_nvm_dev.manual_page_write == false) && (length < NVMCTRL_PAGE_SIZE)) { +#ifdef FEATURE_NVM_RWWEE + return ((is_rww_eeprom) ? + (nvm_execute_command(NVM_COMMAND_RWWEE_WRITE_PAGE,destination_address, 0)): + (nvm_execute_command(NVM_COMMAND_WRITE_PAGE,destination_address, 0))); +#else + return nvm_execute_command(NVM_COMMAND_WRITE_PAGE, + destination_address, 0); +#endif + } + + return STATUS_OK; +} + +/** + * \brief Reads a number of bytes from a page in the NVM memory region. + * + * Reads a given number of bytes from a given page address in the NVM memory + * space into a buffer. + * + * \param[in] source_address Source page address to read from + * \param[out] buffer Pointer to a buffer where the content of the read + * page will be stored + * \param[in] length Number of bytes in the page to read + * + * \return Status of the page read attempt. + * + * \retval STATUS_OK Requested NVM memory page was successfully + * read + * \retval STATUS_BUSY NVM controller was busy when the operation + * was attempted + * \retval STATUS_ERR_BAD_ADDRESS The requested address was outside the + * acceptable range of the NVM memory region or + * not aligned to the start of a page + * \retval STATUS_ERR_INVALID_ARG The supplied read length was invalid + */ +enum status_code nvm_read_buffer( + const uint32_t source_address, + uint8_t *const buffer, + uint16_t length) +{ + /* Check if the source address is valid */ + if (source_address > + ((uint32_t)_nvm_dev.page_size * _nvm_dev.number_of_pages)) { +#ifdef FEATURE_NVM_RWWEE + if (source_address >= ((uint32_t)NVMCTRL_RWW_EEPROM_SIZE + NVMCTRL_RWW_EEPROM_ADDR) + || source_address < NVMCTRL_RWW_EEPROM_ADDR){ + return STATUS_ERR_BAD_ADDRESS; + } +#else + return STATUS_ERR_BAD_ADDRESS; +#endif + } + + /* Check if the read address is not aligned to the start of a page */ + if (source_address & (_nvm_dev.page_size - 1)) { + return STATUS_ERR_BAD_ADDRESS; + } + + /* Check if the write length is longer than an NVM page */ + if (length > _nvm_dev.page_size) { + return STATUS_ERR_INVALID_ARG; + } + + /* Get a pointer to the module hardware instance */ + Nvmctrl *const nvm_module = NVMCTRL; + + /* Check if the module is busy */ + if (!nvm_is_ready()) { + return STATUS_BUSY; + } + + /* Clear error flags */ + nvm_module->STATUS.reg = NVMCTRL_STATUS_MASK; + + uint32_t page_address = source_address / 2; + + /* NVM _must_ be accessed as a series of 16-bit words, perform manual copy + * to ensure alignment */ + for (uint16_t i = 0; i < length; i += 2) { + /* Fetch next 16-bit chunk from the NVM memory space */ + uint16_t data = NVM_MEMORY[page_address++]; + + /* Copy first byte of the 16-bit chunk to the destination buffer */ + buffer[i] = (data & 0xFF); + + /* If we are not at the end of a read request with an odd byte count, + * store the next byte of data as well */ + if (i < (length - 1)) { + buffer[i + 1] = (data >> 8); + } + } + + return STATUS_OK; +} + +/** + * \brief Erases a row in the NVM memory space. + * + * Erases a given row in the NVM memory region. + * + * \param[in] row_address Address of the row to erase + * + * \return Status of the NVM row erase attempt. + * + * \retval STATUS_OK Requested NVM memory row was successfully + * erased + * \retval STATUS_BUSY NVM controller was busy when the operation + * was attempted + * \retval STATUS_ERR_BAD_ADDRESS The requested row address was outside the + * acceptable range of the NVM memory region or + * not aligned to the start of a row + * \retval STATUS_ABORTED NVM erased error + */ +enum status_code nvm_erase_row( + const uint32_t row_address) +{ +#ifdef FEATURE_NVM_RWWEE + bool is_rww_eeprom = false; +#endif + + /* Check if the row address is valid */ + if (row_address > + ((uint32_t)_nvm_dev.page_size * _nvm_dev.number_of_pages)) { +#ifdef FEATURE_NVM_RWWEE + if (row_address >= ((uint32_t)NVMCTRL_RWW_EEPROM_SIZE + NVMCTRL_RWW_EEPROM_ADDR) + || row_address < NVMCTRL_RWW_EEPROM_ADDR){ + return STATUS_ERR_BAD_ADDRESS; + } + is_rww_eeprom = true; +#else + return STATUS_ERR_BAD_ADDRESS; +#endif + } + + /* Check if the address to erase is not aligned to the start of a row */ + if (row_address & ((_nvm_dev.page_size * NVMCTRL_ROW_PAGES) - 1)) { + return STATUS_ERR_BAD_ADDRESS; + } + + /* Get a pointer to the module hardware instance */ + Nvmctrl *const nvm_module = NVMCTRL; + + /* Check if the module is busy */ + if (!nvm_is_ready()) { + return STATUS_BUSY; + } + + /* Clear error flags */ + nvm_module->STATUS.reg = NVMCTRL_STATUS_MASK; + + /* Set address and command */ + nvm_module->ADDR.reg = (uintptr_t)&NVM_MEMORY[row_address / 4]; + +#ifdef SAMD21_64K + if (is_rww_eeprom) { + NVM_MEMORY[row_address / 2] = 0x0; + } +#endif + +#ifdef FEATURE_NVM_RWWEE + if (is_rww_eeprom) { + /* Disable Cache */ + nvm_module->CTRLB.bit.CACHEDIS = 1; + nvm_module->CTRLB.reg; + + /* Set command */ + nvm_module->CTRLA.reg = NVM_COMMAND_RWWEE_ERASE_ROW | NVMCTRL_CTRLA_CMDEX_KEY; + } + else{ + /* Set command */ + nvm_module->CTRLA.reg = NVM_COMMAND_ERASE_ROW | NVMCTRL_CTRLA_CMDEX_KEY; + } +#else + nvm_module->CTRLA.reg = NVM_COMMAND_ERASE_ROW | NVMCTRL_CTRLA_CMDEX_KEY; +#endif + + while (!nvm_is_ready()) { + } + +#ifdef FEATURE_NVM_RWWEE + if (is_rww_eeprom) { + /* Enable Cache */ + nvm_module->CTRLB.bit.CACHEDIS = 0; + } +#endif + + /* There existed error in NVM erase operation */ + if ((enum nvm_error)(nvm_module->STATUS.reg & NVM_ERRORS_MASK) != NVM_ERROR_NONE) { + return STATUS_ABORTED; + } + + return STATUS_OK; +} + +/** + * \brief Reads the parameters of the NVM controller. + * + * Retrieves the page size, number of pages, and other configuration settings + * of the NVM region. + * + * \param[out] parameters Parameter structure, which holds page size and + * number of pages in the NVM memory + */ +void nvm_get_parameters( + struct nvm_parameters *const parameters) +{ + /* Sanity check parameters */ + Assert(parameters); + + /* Get a pointer to the module hardware instance */ + Nvmctrl *const nvm_module = NVMCTRL; + + /* Clear error flags */ + nvm_module->STATUS.reg = NVMCTRL_STATUS_MASK; + + /* Read out from the PARAM register */ + uint32_t param_reg = nvm_module->PARAM.reg; + + /* Mask out page size exponent and convert to a number of bytes */ + parameters->page_size = + 8 << ((param_reg & NVMCTRL_PARAM_PSZ_Msk) >> NVMCTRL_PARAM_PSZ_Pos); + + /* Mask out number of pages count */ + parameters->nvm_number_of_pages = + (param_reg & NVMCTRL_PARAM_NVMP_Msk) >> NVMCTRL_PARAM_NVMP_Pos; + +#ifdef FEATURE_NVM_RWWEE + /* Mask out rwwee number of pages count */ + parameters->rww_eeprom_number_of_pages = + (param_reg & NVMCTRL_PARAM_RWWEEP_Msk) >> NVMCTRL_PARAM_RWWEEP_Pos; +#endif + + /* Read the current EEPROM fuse value from the USER row */ + uint16_t eeprom_fuse_value = + (NVM_USER_MEMORY[NVMCTRL_FUSES_EEPROM_SIZE_Pos / 16] & + NVMCTRL_FUSES_EEPROM_SIZE_Msk) >> NVMCTRL_FUSES_EEPROM_SIZE_Pos; + + /* Translate the EEPROM fuse byte value to a number of NVM pages */ + if (eeprom_fuse_value == 7) { + parameters->eeprom_number_of_pages = 0; + } + else { + parameters->eeprom_number_of_pages = + NVMCTRL_ROW_PAGES << (6 - eeprom_fuse_value); + } + + /* Read the current BOOTSZ fuse value from the USER row */ + uint16_t boot_fuse_value = + (NVM_USER_MEMORY[NVMCTRL_FUSES_BOOTPROT_Pos / 16] & + NVMCTRL_FUSES_BOOTPROT_Msk) >> NVMCTRL_FUSES_BOOTPROT_Pos; + + /* Translate the BOOTSZ fuse byte value to a number of NVM pages */ + if (boot_fuse_value == 7) { + parameters->bootloader_number_of_pages = 0; + } + else { + parameters->bootloader_number_of_pages = + NVMCTRL_ROW_PAGES << (7 - boot_fuse_value); + } +} + +/** + * \brief Checks whether the page region is locked. + * + * Extracts the region to which the given page belongs and checks whether + * that region is locked. + * + * \param[in] page_number Page number to be checked + * + * \return Page lock status. + * + * \retval true Page is locked + * \retval false Page is not locked + * + */ +bool nvm_is_page_locked(uint16_t page_number) +{ + uint16_t pages_in_region; + uint16_t region_number; + +#ifdef FEATURE_NVM_RWWEE + Assert(page_number < _nvm_dev.number_of_pages); +#endif + + /* Get a pointer to the module hardware instance */ + Nvmctrl *const nvm_module = NVMCTRL; + + /* Get number of pages in a region */ + pages_in_region = _nvm_dev.number_of_pages / 16; + + /* Get region for given page */ + region_number = page_number / pages_in_region; + + return !(nvm_module->LOCK.reg & (1 << region_number)); +} + +///@cond INTERNAL + +/** + * \internal + * + * \brief Translate fusebit words into struct content. + * + */ +static void _nvm_translate_raw_fusebits_to_struct ( + uint32_t *raw_user_row, + struct nvm_fusebits *fusebits) +{ + + fusebits->bootloader_size = (enum nvm_bootloader_size) + ((raw_user_row[0] & NVMCTRL_FUSES_BOOTPROT_Msk) + >> NVMCTRL_FUSES_BOOTPROT_Pos); + + fusebits->eeprom_size = (enum nvm_eeprom_emulator_size) + ((raw_user_row[0] & NVMCTRL_FUSES_EEPROM_SIZE_Msk) + >> NVMCTRL_FUSES_EEPROM_SIZE_Pos); + +#if (SAML21) || (SAML22) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + fusebits->bod33_level = (uint8_t) + ((raw_user_row[0] & FUSES_BOD33USERLEVEL_Msk) + >> FUSES_BOD33USERLEVEL_Pos); + + fusebits->bod33_enable = (bool) + (!((raw_user_row[0] & FUSES_BOD33_DIS_Msk) + >> FUSES_BOD33_DIS_Pos)); + + fusebits->bod33_action = (enum nvm_bod33_action) + ((raw_user_row[0] & FUSES_BOD33_ACTION_Msk) + >> FUSES_BOD33_ACTION_Pos); + + fusebits->bod33_hysteresis = (bool) + ((raw_user_row[1] & FUSES_BOD33_HYST_Msk) + >> FUSES_BOD33_HYST_Pos); + +#elif (SAMD20) || (SAMD21) || (SAMR21)|| (SAMDA1) || (SAMD09) || (SAMD10) || (SAMD11) || (SAMHA1) || (SAMHA0) + fusebits->bod33_level = (uint8_t) + ((raw_user_row[0] & FUSES_BOD33USERLEVEL_Msk) + >> FUSES_BOD33USERLEVEL_Pos); + + fusebits->bod33_enable = (bool) + ((raw_user_row[0] & FUSES_BOD33_EN_Msk) + >> FUSES_BOD33_EN_Pos); + + fusebits->bod33_action = (enum nvm_bod33_action) + ((raw_user_row[0] & FUSES_BOD33_ACTION_Msk) + >> FUSES_BOD33_ACTION_Pos); + fusebits->bod33_hysteresis = (bool) + ((raw_user_row[1] & FUSES_BOD33_HYST_Msk) + >> FUSES_BOD33_HYST_Pos); +#elif (SAMC20) || (SAMC21) + fusebits->bodvdd_level = (uint8_t) + ((raw_user_row[0] & FUSES_BODVDDUSERLEVEL_Msk) + >> FUSES_BODVDDUSERLEVEL_Pos); + + fusebits->bodvdd_enable = (bool) + (!((raw_user_row[0] & FUSES_BODVDD_DIS_Msk) + >> FUSES_BODVDD_DIS_Pos)); + + fusebits->bodvdd_action = (enum nvm_bod33_action) + ((raw_user_row[0] & FUSES_BODVDD_ACTION_Msk) + >> FUSES_BODVDD_ACTION_Pos); + + fusebits->bodvdd_hysteresis = (raw_user_row[1] & FUSES_BODVDD_HYST_Msk) + >> FUSES_BODVDD_HYST_Pos; +#endif + +#ifdef FEATURE_BOD12 + +#ifndef FUSES_BOD12USERLEVEL_Pos +#define FUSES_BOD12USERLEVEL_Pos 17 +#define FUSES_BOD12USERLEVEL_Msk (0x3Ful << FUSES_BOD12USERLEVEL_Pos) +#endif +#ifndef FUSES_BOD12_DIS_Pos +#define FUSES_BOD12_DIS_Pos 23 +#define FUSES_BOD12_DIS_Msk (0x1ul << FUSES_BOD12_DIS_Pos) +#endif +#ifndef FUSES_BOD12_ACTION_Pos +#define FUSES_BOD12_ACTION_Pos 24 +#define FUSES_BOD12_ACTION_Msk (0x3ul << FUSES_BOD12_ACTION_Pos) +#endif + + fusebits->bod12_level = (uint8_t) + ((raw_user_row[0] & FUSES_BOD12USERLEVEL_Msk) + >> FUSES_BOD12USERLEVEL_Pos); + + fusebits->bod12_enable = (bool) + (!((raw_user_row[0] & FUSES_BOD12_DIS_Msk) + >> FUSES_BOD12_DIS_Pos)); + + fusebits->bod12_action = (enum nvm_bod12_action) + ((raw_user_row[0] & FUSES_BOD12_ACTION_Msk) + >> FUSES_BOD33_ACTION_Pos); + + fusebits->bod12_hysteresis = (bool) + ((raw_user_row[1] & FUSES_BOD12_HYST_Msk) + >> FUSES_BOD12_HYST_Pos); +#endif + + fusebits->wdt_enable = (bool) + ((raw_user_row[0] & WDT_FUSES_ENABLE_Msk) >> WDT_FUSES_ENABLE_Pos); + + fusebits->wdt_always_on = (bool) + ((raw_user_row[0] & WDT_FUSES_ALWAYSON_Msk) >> WDT_FUSES_ALWAYSON_Pos); + + fusebits->wdt_timeout_period = (uint8_t) + ((raw_user_row[0] & WDT_FUSES_PER_Msk) >> WDT_FUSES_PER_Pos); + +#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + fusebits->wdt_window_timeout = (enum nvm_wdt_window_timeout) + ((raw_user_row[1] & WDT_FUSES_WINDOW_Msk) >> WDT_FUSES_WINDOW_Pos); +#else + /* WDT Windows timout lay between two 32-bit words in the user row. Because only one bit lays in word[0], + bits in word[1] must be left sifted by one to make the correct number */ + fusebits->wdt_window_timeout = (enum nvm_wdt_window_timeout) + (((raw_user_row[0] & WDT_FUSES_WINDOW_0_Msk) >> WDT_FUSES_WINDOW_0_Pos) | + ((raw_user_row[1] & WDT_FUSES_WINDOW_1_Msk) << 1)); +#endif + fusebits->wdt_early_warning_offset = (enum nvm_wdt_early_warning_offset) + ((raw_user_row[1] & WDT_FUSES_EWOFFSET_Msk) >> WDT_FUSES_EWOFFSET_Pos); + + fusebits->wdt_window_mode_enable_at_poweron = (bool) + ((raw_user_row[1] & WDT_FUSES_WEN_Msk) >> WDT_FUSES_WEN_Pos); + + fusebits->lockbits = (uint16_t) + ((raw_user_row[1] & NVMCTRL_FUSES_REGION_LOCKS_Msk) + >> NVMCTRL_FUSES_REGION_LOCKS_Pos); + +} + +///@endcond + +/** + * \brief Get fuses from user row. + * + * Read out the fuse settings from the user row. + * + * \param[in] fusebits Pointer to a 64-bit wide memory buffer of type struct nvm_fusebits + * + * \return Status of read fuses attempt. + * + * \retval STATUS_OK This function will always return STATUS_OK + */ +enum status_code nvm_get_fuses ( + struct nvm_fusebits *fusebits) +{ + enum status_code error_code = STATUS_OK; + uint32_t raw_fusebits[2]; + + /* Make sure the module is ready */ + while (!nvm_is_ready()) { + } + + /* Read the fuse settings in the user row, 64 bit */ + ((uint16_t*)&raw_fusebits)[0] = (uint16_t)NVM_MEMORY[NVMCTRL_USER / 2]; + ((uint16_t*)&raw_fusebits)[1] = (uint16_t)NVM_MEMORY[(NVMCTRL_USER / 2) + 1]; + ((uint16_t*)&raw_fusebits)[2] = (uint16_t)NVM_MEMORY[(NVMCTRL_USER / 2) + 2]; + ((uint16_t*)&raw_fusebits)[3] = (uint16_t)NVM_MEMORY[(NVMCTRL_USER / 2) + 3]; + + _nvm_translate_raw_fusebits_to_struct(raw_fusebits, fusebits); + + return error_code; +} + +/** + * \brief Set fuses from user row. + * + * Set fuse settings from the user row. + * + * \note When writing to the user row, the values do not get loaded by the + * other modules on the device until a device reset occurs. + * + * \param[in] fusebits Pointer to a 64-bit wide memory buffer of type struct nvm_fusebits + * + * \return Status of read fuses attempt. + * + * \retval STATUS_OK This function will always return STATUS_OK + * + * \retval STATUS_BUSY If the NVM controller was already busy + * executing a command when the new command + * was issued + * \retval STATUS_ERR_IO If the command was invalid due to memory or + * security locking + * \retval STATUS_ERR_INVALID_ARG If the given command was invalid or + * unsupported + * \retval STATUS_ERR_BAD_ADDRESS If the given address was invalid + */ + +enum status_code nvm_set_fuses(struct nvm_fusebits *fb) +{ + uint32_t fusebits[2]; + enum status_code error_code = STATUS_OK; + + if (fb == NULL) { + return STATUS_ERR_INVALID_ARG; + } + /* Read the fuse settings in the user row, 64 bit */ + fusebits[0] = *((uint32_t *)NVMCTRL_AUX0_ADDRESS); + fusebits[1] = *(((uint32_t *)NVMCTRL_AUX0_ADDRESS) + 1); + + /* Set user fuses bit */ + fusebits[0] &= (~NVMCTRL_FUSES_BOOTPROT_Msk); + fusebits[0] |= NVMCTRL_FUSES_BOOTPROT(fb->bootloader_size); + + fusebits[0] &= (~NVMCTRL_FUSES_EEPROM_SIZE_Msk); + fusebits[0] |= NVMCTRL_FUSES_EEPROM_SIZE(fb->eeprom_size); + +#if (SAML21) || (SAML22) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + fusebits[0] &= (~FUSES_BOD33USERLEVEL_Msk); + fusebits[0] |= FUSES_BOD33USERLEVEL(fb->bod33_level); + + fusebits[0] &= (~FUSES_BOD33_DIS_Msk); + fusebits[0] |= (!fb->bod33_enable) << FUSES_BOD33_DIS_Pos; + + fusebits[0] &= (~FUSES_BOD33_ACTION_Msk); + fusebits[0] |= fb->bod33_action << FUSES_BOD33_ACTION_Pos; + + fusebits[1] &= (~FUSES_BOD33_HYST_Msk); + fusebits[1] |= fb->bod33_hysteresis << FUSES_BOD33_HYST_Pos; + +#elif (SAMD20) || (SAMD21) || (SAMR21) || (SAMDA1) || (SAMD09) || (SAMD10) || (SAMD11) || (SAMHA1) || (SAMHA0) + fusebits[0] &= (~FUSES_BOD33USERLEVEL_Msk); + fusebits[0] |= FUSES_BOD33USERLEVEL(fb->bod33_level); + + fusebits[0] &= (~FUSES_BOD33_EN_Msk); + fusebits[0] |= (fb->bod33_enable) << FUSES_BOD33_EN_Pos; + + fusebits[0] &= (~FUSES_BOD33_ACTION_Msk); + fusebits[0] |= fb->bod33_action << FUSES_BOD33_ACTION_Pos; + + fusebits[1] &= (~FUSES_BOD33_HYST_Msk); + fusebits[1] |= fb->bod33_hysteresis << FUSES_BOD33_HYST_Pos; + +#elif (SAMC20) || (SAMC21) + fusebits[0] &= (~FUSES_BODVDDUSERLEVEL_Msk); + fusebits[0] |= FUSES_BODVDDUSERLEVEL(fb->bodvdd_level); + + fusebits[0] &= (~FUSES_BODVDD_DIS_Msk); + fusebits[0] |= (!fb->bodvdd_enable) << FUSES_BODVDD_DIS_Pos; + + fusebits[0] &= (~FUSES_BODVDD_ACTION_Msk); + fusebits[0] |= fb->bodvdd_action << FUSES_BODVDD_ACTION_Pos; + + fusebits[1] &= (~FUSES_BODVDD_HYST_Msk); + fusebits[1] |= fb->bodvdd_hysteresis << FUSES_BODVDD_HYST_Pos; + +#endif + + fusebits[0] &= (~WDT_FUSES_ENABLE_Msk); + fusebits[0] |= fb->wdt_enable << WDT_FUSES_ENABLE_Pos; + + fusebits[0] &= (~WDT_FUSES_ALWAYSON_Msk); + fusebits[0] |= (fb->wdt_always_on) << WDT_FUSES_ALWAYSON_Pos; + + fusebits[0] &= (~WDT_FUSES_PER_Msk); + fusebits[0] |= fb->wdt_timeout_period << WDT_FUSES_PER_Pos; + +#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + fusebits[1] &= (~WDT_FUSES_WINDOW_Msk); + fusebits[1] |= fb->wdt_window_timeout << WDT_FUSES_WINDOW_Pos; +#else + /* WDT Windows timout lay between two 32-bit words in the user row. the last one bit lays in word[0], + and the other bits in word[1] */ + fusebits[0] &= (~WDT_FUSES_WINDOW_0_Msk); + fusebits[0] |= (fb->wdt_window_timeout & 0x1) << WDT_FUSES_WINDOW_0_Pos; + + fusebits[1] &= (~WDT_FUSES_WINDOW_1_Msk); + fusebits[1] |= (fb->wdt_window_timeout >> 1) << WDT_FUSES_WINDOW_1_Pos; + +#endif + fusebits[1] &= (~WDT_FUSES_EWOFFSET_Msk); + fusebits[1] |= fb->wdt_early_warning_offset << WDT_FUSES_EWOFFSET_Pos; + + fusebits[1] &= (~WDT_FUSES_WEN_Msk); + fusebits[1] |= fb->wdt_window_mode_enable_at_poweron << WDT_FUSES_WEN_Pos; + + fusebits[1] &= (~NVMCTRL_FUSES_REGION_LOCKS_Msk); + fusebits[1] |= fb->lockbits << NVMCTRL_FUSES_REGION_LOCKS_Pos; + +#ifdef FEATURE_BOD12 + +#ifndef FUSES_BOD12USERLEVEL_Pos +#define FUSES_BOD12USERLEVEL_Pos 17 +#define FUSES_BOD12USERLEVEL_Msk (0x3Ful << FUSES_BOD12USERLEVEL_Pos) +#endif +#ifndef FUSES_BOD12_DIS_Pos +#define FUSES_BOD12_DIS_Pos 23 +#define FUSES_BOD12_DIS_Msk (0x1ul << FUSES_BOD12_DIS_Pos) +#endif +#ifndef FUSES_BOD12_ACTION_Pos +#define FUSES_BOD12_ACTION_Pos 24 +#define FUSES_BOD12_ACTION_Msk (0x3ul << FUSES_BOD12_ACTION_Pos) +#endif + + fusebits[0] &= (~FUSES_BOD12USERLEVEL_Msk); + fusebits[0] |= ((FUSES_BOD12USERLEVEL_Msk & ((fb->bod12_level) << + FUSES_BOD12USERLEVEL_Pos))); + + fusebits[0] &= (~FUSES_BOD12_DIS_Msk); + fusebits[0] |= (!fb->bod12_enable) << FUSES_BOD12_DIS_Pos; + + fusebits[0] &= (~FUSES_BOD12_ACTION_Msk); + fusebits[0] |= fb->bod12_action << FUSES_BOD12_ACTION_Pos; + + fusebits[1] &= (~FUSES_BOD12_HYST_Msk); + fusebits[1] |= fb->bod12_hysteresis << FUSES_BOD12_HYST_Pos; +#endif + + error_code = nvm_execute_command(NVM_COMMAND_ERASE_AUX_ROW,NVMCTRL_AUX0_ADDRESS,0); + if (error_code != STATUS_OK) { + return error_code; + } + + error_code = nvm_execute_command(NVM_COMMAND_PAGE_BUFFER_CLEAR,NVMCTRL_AUX0_ADDRESS,0); + if (error_code != STATUS_OK) { + return error_code; + } + + *((uint32_t *)NVMCTRL_AUX0_ADDRESS) = fusebits[0]; + *(((uint32_t *)NVMCTRL_AUX0_ADDRESS) + 1) = fusebits[1]; + + error_code = nvm_execute_command(NVM_COMMAND_WRITE_AUX_ROW,NVMCTRL_AUX0_ADDRESS,0); + if (error_code != STATUS_OK) { + return error_code; + } + + return error_code; +} diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/nvm/nvm.h b/src/boards/mcu/samr34/ASF/sam0/drivers/nvm/nvm.h new file mode 100644 index 000000000..35e8581d2 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/nvm/nvm.h @@ -0,0 +1,937 @@ +/** + * \file + * + * \brief SAM Non-Volatile Memory driver + * + * Copyright (c) 2012-2020 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#ifndef NVM_H_INCLUDED +#define NVM_H_INCLUDED + +/** + * \defgroup asfdoc_sam0_nvm_group SAM Non-Volatile Memory (NVM) Driver + * + * This driver for Atmel® | SMART ARM®-based microcontrollers provides + * an interface for the configuration and management of non-volatile memories + * within the device, for partitioning, erasing, reading, and writing of data. + * + * The following peripheral is used by this module: + * - NVM (Non-Volatile Memory) + * + * The following devices can use this module: + * - Atmel | SMART SAM D20/D21 + * - Atmel | SMART SAM R21 + * - Atmel | SMART SAM D09/D10/D11 + * - Atmel | SMART SAM L21/L22 + * - Atmel | SMART SAM DA1 + * - Atmel | SMART SAM C20/C21 + * - Atmel | SMART SAM HA1 + * - Atmel | SMART SAM R30 + * - Atmel | SMART SAM R34/R35 + * + * The outline of this documentation is as follows: + * - \ref asfdoc_sam0_nvm_prerequisites + * - \ref asfdoc_sam0_nvm_module_overview + * - \ref asfdoc_sam0_nvm_special_considerations + * - \ref asfdoc_sam0_nvm_extra_info + * - \ref asfdoc_sam0_nvm_examples + * - \ref asfdoc_sam0_nvm_api_overview + * + * + * \section asfdoc_sam0_nvm_prerequisites Prerequisites + * + * There are no prerequisites for this module. + * + * + * \section asfdoc_sam0_nvm_module_overview Module Overview + * + * The Non-Volatile Memory (NVM) module provides an interface to the device's + * Non-Volatile Memory controller, so that memory pages can be written, read, + * erased, and reconfigured in a standardized manner. + * + * \subsection asfdoc_sam0_nvm_features Driver Feature Macro Definition + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Driver feature macroSupported devices
FEATURE_NVM_RWWEESAM L21/L22, SAM D21-64K, SAM DA1, SAM C20/C21, SAM R30 , SAM R34/R35
FEATURE_BOD12SAM L21, SAMR30/R34
+ * \note The specific features are only available in the driver when the + * selected device supports those features. + * + * \subsection asfdoc_sam0_nvm_module_overview_regions Memory Regions + * The NVM memory space of the SAM devices is divided into two sections: + * a Main Array section, and an Auxiliary space section. The Main Array space + * can be configured to have an (emulated) EEPROM and/or boot loader section. + * The memory layout with the EEPROM and bootloader partitions is shown in + * \ref asfdoc_sam0_nvm_module_mem_layout "the figure below". + * + * \anchor asfdoc_sam0_nvm_module_mem_layout + * \dot + * digraph memory_layout { + * size="5,5" + * node [shape=plaintext, fontname=arial] + * memory [label=< + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
End of NVM Memory Reserved EEPROM Section
Start of EEPROM Memory
End of Application Memory Application Section
Start of Application Memory
End of Bootloader Memory BOOT Section
Start of NVM Memory
+ * >] + * } + * \enddot + * + * The Main Array is divided into rows and pages, where each row contains four + * pages. The size of each page may vary from 8-1024 bytes dependent of the + * device. Device specific parameters such as the page size and total number of + * pages in the NVM memory space are available via the \ref nvm_get_parameters() + * function. + * + * An NVM page number and address can be computed via the following equations: + * + * \f[ PageNum = (RowNum \times 4) + PagePosInRow \f] + * \f[ PageAddr = PageNum \times PageSize \f] + * + * \ref asfdoc_sam0_nvm_module_row_layout "The figure below" shows an example + * of the memory page and address values associated with logical row 7 of the + * NVM memory space. + * + * \anchor asfdoc_sam0_nvm_module_row_layout + * \dot + * digraph row_layout { + * size="4,4" + * node [shape=plaintext, fontname=arial] + * row [label=< + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Row 0x07 Page 0x1F Page 0x1E Page 0x1D Page 0x1C
Address 0x7C0 0x780 0x740 0x700
+ * >] + * } + * \enddot + * + * \subsection asfdoc_sam0_nvm_module_overview_locking_regions Region Lock Bits + * As mentioned in \ref asfdoc_sam0_nvm_module_overview_regions, the main + * block of the NVM memory is divided into a number of individually addressable + * pages. These pages are grouped into 16 equal sized regions, where each region + * can be locked separately issuing an \ref NVM_COMMAND_LOCK_REGION command or + * by writing the LOCK bits in the User Row. Rows reserved for the EEPROM + * section are not affected by the lock bits or commands. + * + * \note By using the \ref NVM_COMMAND_LOCK_REGION or + * \ref NVM_COMMAND_UNLOCK_REGION commands the settings will remain in + * effect until the next device reset. By changing the default lock + * setting for the regions, the auxiliary space must to be written, + * however the adjusted configuration will not take effect until the next + * device reset. + * + * \note If the \ref asfdoc_sam0_nvm_special_consideration_security_bit is + * set, the auxiliary space cannot be written to. Clearing of the security + * bit can only be performed by a full chip erase. + * + * \subsection asfdoc_sam0_nvm_module_overview_sub_rw Read/Write + * Reading from the NVM memory can be performed using direct addressing into the + * NVM memory space, or by calling the \ref nvm_read_buffer() function. + * + * Writing to the NVM memory must be performed by the \ref nvm_write_buffer() + * function - additionally, a manual page program command must be issued if + * the NVM controller is configured in manual page writing mode. + * + * Before a page can be updated, the associated NVM memory row must be erased + * first via the \ref nvm_erase_row() function. Writing to a non-erased page + * will result in corrupt data being stored in the NVM memory space. + * + * \section asfdoc_sam0_nvm_special_considerations Special Considerations + * + * \subsection asfdoc_sam0_nvm_special_consideration_pageerase Page Erasure + * The granularity of an erase is per row, while the granularity of a write is + * per page. Thus, if the user application is modifying only one page of a row, + * the remaining pages in the row must be buffered and the row erased, as an + * erase is mandatory before writing to a page. + * + * \subsection asfdoc_sam0_nvm_special_consideration_clocks Clocks + * The user must ensure that the driver is configured with a proper number of + * wait states when the CPU is running at high frequencies. + * + * \subsection asfdoc_sam0_nvm_special_consideration_security_bit Security Bit + * The User Row in the Auxiliary Space cannot be read or written when + * the Security Bit is set. The Security Bit can be set by using passing + * \ref NVM_COMMAND_SET_SECURITY_BIT to the \ref nvm_execute_command() function, + * or it will be set if one tries to access a locked region. See + * \ref asfdoc_sam0_nvm_module_overview_locking_regions. + * + * The Security Bit can only be cleared by performing a chip erase. + * + * + * \section asfdoc_sam0_nvm_extra_info Extra Information + * + * For extra information, see \ref asfdoc_sam0_nvm_extra. This includes: + * - \ref asfdoc_sam0_nvm_extra_acronyms + * - \ref asfdoc_sam0_nvm_extra_dependencies + * - \ref asfdoc_sam0_nvm_extra_errata + * - \ref asfdoc_sam0_nvm_extra_history + * + * + * \section asfdoc_sam0_nvm_examples Examples + * + * For a list of examples related to this driver, see + * \ref asfdoc_sam0_nvm_exqsg. + * + * + * \section asfdoc_sam0_nvm_api_overview API Overview + * @{ + */ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Define SAMD21-64K devices */ +#if defined(SAMD21E15L) || defined(SAMD21E16L) || defined(__SAMD21E15L__) || defined(__SAMD21E16L__) \ + || defined(SAMD21E15B) || defined(SAMD21E16B) || defined(__SAMD21E15B__) || defined(__SAMD21E16B__) \ + || defined(SAMD21E15BU) || defined(SAMD21E16BU) || defined(__SAMD21E15BU__) || defined(__SAMD21E16BU__) \ + || defined(SAMD21G15L) || defined(SAMD21G16L) || defined(__SAMD21G15L__) || defined(__SAMD21G16L__) \ + || defined(SAMD21G15B) || defined(SAMD21G16B) || defined(__SAMD21G15B__) || defined(__SAMD21G16B__) \ + || defined(SAMD21J15B) || defined(SAMD21J16B) || defined(__SAMD21J15B__) || defined(__SAMD21J16B__) + +# define SAMD21_64K + +#endif + +/** + * \name Driver Feature Definition + * + * Define NVM features set according to the different device families. + * @{ +*/ +#if (SAML21) || (SAML22) || (SAMDA1) || (SAMC20) || (SAMC21) || (SAMR30) || (SAMR34) || (SAMR35) || defined(SAMD21_64K) || (SAMHA1) || (WLR089) || (SAMR34) \ + || defined(__DOXYGEN__) +/** Read while write EEPROM emulation feature. */ +# define FEATURE_NVM_RWWEE +#endif +#if (SAML21) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) || defined(__DOXYGEN__) +/** Brown-out detector internal to the voltage regulator for VDDCORE. */ +#define FEATURE_BOD12 +#endif +/*@}*/ + +#if !defined(__DOXYGEN__) +/** + * \brief Mask for the error flags in the status register. + */ +# define NVM_ERRORS_MASK (NVMCTRL_STATUS_PROGE | \ + NVMCTRL_STATUS_LOCKE | \ + NVMCTRL_STATUS_NVME) +#endif + +/** + * \brief NVM error flags. + * + * Possible NVM controller error codes, which can be returned by the NVM + * controller after a command is issued. + */ +enum nvm_error { + /** No errors */ + NVM_ERROR_NONE = 0, + /** Lock error, a locked region was attempted accessed */ + NVM_ERROR_LOCK = NVMCTRL_STATUS_NVME | NVMCTRL_STATUS_LOCKE, + /** Program error, invalid command was executed */ + NVM_ERROR_PROG = NVMCTRL_STATUS_NVME | NVMCTRL_STATUS_PROGE, +}; + +/** + * \brief NVM controller commands. + */ +enum nvm_command { + /** Erases the addressed memory row */ + NVM_COMMAND_ERASE_ROW = NVMCTRL_CTRLA_CMD_ER, + + /** Write the contents of the page buffer to the addressed memory page */ + NVM_COMMAND_WRITE_PAGE = NVMCTRL_CTRLA_CMD_WP, + + /** Erases the addressed auxiliary memory row. + * + * \note This command can only be given when the security bit is not set. + */ + NVM_COMMAND_ERASE_AUX_ROW = NVMCTRL_CTRLA_CMD_EAR, + + /** Write the contents of the page buffer to the addressed auxiliary memory + * row. + * + * \note This command can only be given when the security bit is not set. + */ + NVM_COMMAND_WRITE_AUX_ROW = NVMCTRL_CTRLA_CMD_WAP, + + /** Locks the addressed memory region, preventing further modifications + * until the region is unlocked or the device is erased + */ + NVM_COMMAND_LOCK_REGION = NVMCTRL_CTRLA_CMD_LR, + + /** Unlocks the addressed memory region, allowing the region contents to be + * modified + */ + NVM_COMMAND_UNLOCK_REGION = NVMCTRL_CTRLA_CMD_UR, + + /** Clears the page buffer of the NVM controller, resetting the contents to + * all zero values + */ + NVM_COMMAND_PAGE_BUFFER_CLEAR = NVMCTRL_CTRLA_CMD_PBC, + + /** Sets the device security bit, disallowing the changing of lock bits and + * auxiliary row data until a chip erase has been performed + */ + NVM_COMMAND_SET_SECURITY_BIT = NVMCTRL_CTRLA_CMD_SSB, + + /** Enter power reduction mode in the NVM controller to reduce the power + * consumption of the system + */ + NVM_COMMAND_ENTER_LOW_POWER_MODE = NVMCTRL_CTRLA_CMD_SPRM, + + /** Exit power reduction mode in the NVM controller to allow other NVM + * commands to be issued + */ + NVM_COMMAND_EXIT_LOW_POWER_MODE = NVMCTRL_CTRLA_CMD_CPRM, +#ifdef FEATURE_NVM_RWWEE + /** Read while write (RWW) EEPROM area erase row */ + NVM_COMMAND_RWWEE_ERASE_ROW = NVMCTRL_CTRLA_CMD_RWWEEER, + /** RWW EEPROM write page */ + NVM_COMMAND_RWWEE_WRITE_PAGE = NVMCTRL_CTRLA_CMD_RWWEEWP, +#endif +}; + +/** + * \brief NVM controller power reduction mode configurations. + * + * Power reduction modes of the NVM controller, to conserve power while the + * device is in sleep. + */ +enum nvm_sleep_power_mode { + /** NVM controller exits low-power mode on first access after sleep */ + NVM_SLEEP_POWER_MODE_WAKEONACCESS = NVMCTRL_CTRLB_SLEEPPRM_WAKEONACCESS_Val, + /** NVM controller exits low-power mode when the device exits sleep mode */ + NVM_SLEEP_POWER_MODE_WAKEUPINSTANT = NVMCTRL_CTRLB_SLEEPPRM_WAKEUPINSTANT_Val, + /** Power reduction mode in the NVM controller disabled */ + NVM_SLEEP_POWER_MODE_ALWAYS_AWAKE = NVMCTRL_CTRLB_SLEEPPRM_DISABLED_Val, +}; + +/** + * \brief NVM controller cache readmode configuration. + * + * Control how the NVM cache prefetch data from flash. + * + */ +enum nvm_cache_readmode { + /** The NVM Controller (cache system) does not insert wait states on + * a cache miss. Gives the best system performance. + */ + NVM_CACHE_READMODE_NO_MISS_PENALTY, + /** Reduces power consumption of the cache system, but inserts a + * wait state each time there is a cache miss + */ + NVM_CACHE_READMODE_LOW_POWER, + /** The cache system ensures that a cache hit or miss takes the same + * amount of time, determined by the number of programmed flash + * wait states + */ + NVM_CACHE_READMODE_DETERMINISTIC, +}; + +/** + * \brief NVM controller configuration structure. + * + * Configuration structure for the NVM controller within the device. + */ +struct nvm_config { + /** Power reduction mode during device sleep */ + enum nvm_sleep_power_mode sleep_power_mode; + /** Manual write mode; if enabled, pages loaded into the NVM buffer will + * not be written until a separate write command is issued. If disabled, + * writing to the last byte in the NVM page buffer will trigger an automatic + * write. + * + * \note If a partial page is to be written, a manual write command must be + * executed in either mode. + */ + bool manual_page_write; + /** Number of wait states to insert when reading from flash, to prevent + * invalid data from being read at high clock frequencies + */ + uint8_t wait_states; + + /** + * Setting this to true will disable the pre-fetch cache in front of the + * NVM controller + */ + bool disable_cache; +#if (SAMC20) || (SAMC21) + /** + * Setting this to true will disable the pre-fetch RWW cache in front of the + * NVM controller. + * If RWW cache is enabled, NVM cache will also be enabled. + */ + bool disable_rww_cache; +#endif + /** + * Select the mode for how the cache will pre-fetch data from the flash + */ + enum nvm_cache_readmode cache_readmode; +}; + +/** + * \brief NVM memory parameter structure. + * + * Structure containing the memory layout parameters of the NVM module. + */ +struct nvm_parameters { + /** Number of bytes per page */ + uint8_t page_size; + /** Number of pages in the main array */ + uint16_t nvm_number_of_pages; + /** Size of the emulated EEPROM memory section configured in the NVM + * auxiliary memory space */ + uint32_t eeprom_number_of_pages; + /** Size of the Bootloader memory section configured in the NVM auxiliary + * memory space */ + uint32_t bootloader_number_of_pages; +#ifdef FEATURE_NVM_RWWEE + /** Number of pages in read while write EEPROM (RWWEE) emulation area */ + uint16_t rww_eeprom_number_of_pages; +#endif +}; + +/** + * \brief Bootloader size. + * + * Available bootloader protection sizes in kilobytes. + * + */ +enum nvm_bootloader_size { + /** Boot Loader Size is 32768 bytes */ + NVM_BOOTLOADER_SIZE_128, + /** Boot Loader Size is 16384 bytes */ + NVM_BOOTLOADER_SIZE_64, + /** Boot Loader Size is 8192 bytes */ + NVM_BOOTLOADER_SIZE_32, + /** Boot Loader Size is 4096 bytes */ + NVM_BOOTLOADER_SIZE_16, + /** Boot Loader Size is 2048 bytes */ + NVM_BOOTLOADER_SIZE_8, + /** Boot Loader Size is 1024 bytes */ + NVM_BOOTLOADER_SIZE_4, + /** Boot Loader Size is 512 bytes */ + NVM_BOOTLOADER_SIZE_2, + /** Boot Loader Size is 0 bytes */ + NVM_BOOTLOADER_SIZE_0, +}; + +/** + * \brief EEPROM emulator size. + * + * Available space in flash dedicated for EEPROM emulator in bytes. + * + */ +enum nvm_eeprom_emulator_size { + /** EEPROM Size for EEPROM emulation is 16384 bytes */ + NVM_EEPROM_EMULATOR_SIZE_16384, + /** EEPROM Size for EEPROM emulation is 8192 bytes */ + NVM_EEPROM_EMULATOR_SIZE_8192, + /** EEPROM Size for EEPROM emulation is 4096 bytes */ + NVM_EEPROM_EMULATOR_SIZE_4096, + /** EEPROM Size for EEPROM emulation is 2048 bytes */ + NVM_EEPROM_EMULATOR_SIZE_2048, + /** EEPROM Size for EEPROM emulation is 1024 bytes */ + NVM_EEPROM_EMULATOR_SIZE_1024, + /** EEPROM Size for EEPROM emulation is 512 bytes */ + NVM_EEPROM_EMULATOR_SIZE_512, + /** EEPROM Size for EEPROM emulation is 256 bytes */ + NVM_EEPROM_EMULATOR_SIZE_256, + /** EEPROM Size for EEPROM emulation is 0 bytes */ + NVM_EEPROM_EMULATOR_SIZE_0, +}; + +/** + * \brief BOD33 Action. + * + * What action should be triggered when BOD33 is detected. + * + */ +enum nvm_bod33_action { + /** No action */ + NVM_BOD33_ACTION_NONE, + /** The BOD33 generates a reset */ + NVM_BOD33_ACTION_RESET, + /** The BOD33 generates an interrupt */ + NVM_BOD33_ACTION_INTERRUPT, +}; + +#ifdef FEATURE_BOD12 +/** + * \brief BOD12 Action. + * + * What action should be triggered when BOD12 is detected. + * + */ +enum nvm_bod12_action { + /** No action */ + NVM_BOD12_ACTION_NONE, + /** The BOD12 generates a reset */ + NVM_BOD12_ACTION_RESET, + /** The BOD12 generates an interrupt */ + NVM_BOD12_ACTION_INTERRUPT, +}; +#endif + +/** + * \brief WDT Window time-out period. + * + * Window mode time-out period in clock cycles. + * + */ +enum nvm_wdt_window_timeout { + /** 8 clock cycles */ + NVM_WDT_WINDOW_TIMEOUT_PERIOD_8, + /** 16 clock cycles */ + NVM_WDT_WINDOW_TIMEOUT_PERIOD_16, + /** 32 clock cycles */ + NVM_WDT_WINDOW_TIMEOUT_PERIOD_32, + /** 64 clock cycles */ + NVM_WDT_WINDOW_TIMEOUT_PERIOD_64, + /** 128 clock cycles */ + NVM_WDT_WINDOW_TIMEOUT_PERIOD_128, + /** 256 clock cycles */ + NVM_WDT_WINDOW_TIMEOUT_PERIOD_256, + /** 512 clock cycles */ + NVM_WDT_WINDOW_TIMEOUT_PERIOD_512, + /** 1024 clock cycles */ + NVM_WDT_WINDOW_TIMEOUT_PERIOD_1024, + /** 2048 clock cycles */ + NVM_WDT_WINDOW_TIMEOUT_PERIOD_2048, + /** 4096 clock cycles */ + NVM_WDT_WINDOW_TIMEOUT_PERIOD_4096, + /** 8192 clock cycles */ + NVM_WDT_WINDOW_TIMEOUT_PERIOD_8192, + /** 16384 clock cycles */ + NVM_WDT_WINDOW_TIMEOUT_PERIOD_16384, +}; + +/** + * \brief WDT Early warning offset. + * + * This setting determine how many GCLK_WDT cycles before a watchdog time-out period + * an early warning interrupt should be triggered. + * + */ +enum nvm_wdt_early_warning_offset { + /** 8 clock cycles */ + NVM_WDT_EARLY_WARNING_OFFSET_8, + /** 16 clock cycles */ + NVM_WDT_EARLY_WARNING_OFFSET_16, + /** 32 clock cycles */ + NVM_WDT_EARLY_WARNING_OFFSET_32, + /** 64 clock cycles */ + NVM_WDT_EARLY_WARNING_OFFSET_64, + /** 128 clock cycles */ + NVM_WDT_EARLY_WARNING_OFFSET_128, + /** 256 clock cycles */ + NVM_WDT_EARLY_WARNING_OFFSET_256, + /** 512 clock cycles */ + NVM_WDT_EARLY_WARNING_OFFSET_512, + /** 1024 clock cycles */ + NVM_WDT_EARLY_WARNING_OFFSET_1024, + /** 2048 clock cycles */ + NVM_WDT_EARLY_WARNING_OFFSET_2048, + /** 4096 clock cycles */ + NVM_WDT_EARLY_WARNING_OFFSET_4096, + /** 8192 clock cycles */ + NVM_WDT_EARLY_WARNING_OFFSET_8192, + /** 16384 clock cycles */ + NVM_WDT_EARLY_WARNING_OFFSET_16384, +}; + +/** + * \brief NVM user row fuse setting structure. + * + * This structure contain the layout of the first 64 bits of the user row + * which contain the fuse settings. + */ +struct nvm_fusebits { + /** Bootloader size */ + enum nvm_bootloader_size bootloader_size; + /** EEPROM emulation area size */ + enum nvm_eeprom_emulator_size eeprom_size; +#if (SAMC20) || (SAMC21) + /** BODVDD Threshold level at power on */ + uint8_t bodvdd_level; + /** BODVDD Enable at power on */ + bool bodvdd_enable; + /** BODVDD Action at power on */ + enum nvm_bod33_action bodvdd_action; + /* BODVDD Hysteresis at power on */ + bool bodvdd_hysteresis; +#else + /** BOD33 Threshold level at power on */ + uint8_t bod33_level; + /** BOD33 Enable at power on */ + bool bod33_enable; + /** BOD33 Action at power on */ + enum nvm_bod33_action bod33_action; + /* BOD33 Hysteresis at power on */ + bool bod33_hysteresis; +#endif + /** WDT Enable at power on */ + bool wdt_enable; + /** WDT Always-on at power on */ + bool wdt_always_on; + /** WDT Period at power on */ + uint8_t wdt_timeout_period; + /** WDT Window mode time-out at power on */ + enum nvm_wdt_window_timeout wdt_window_timeout; + /** WDT Early warning interrupt time offset at power on */ + enum nvm_wdt_early_warning_offset wdt_early_warning_offset; + /** WDT Window mode enabled at power on */ + bool wdt_window_mode_enable_at_poweron; + /** NVM Lock bits */ + uint16_t lockbits; +#ifdef FEATURE_BOD12 + /** BOD12 Threshold level at power on */ + uint8_t bod12_level; + /** BOD12 Enable at power on */ + bool bod12_enable; + /** BOD12 Action at power on */ + enum nvm_bod12_action bod12_action; + /* BOD12 Hysteresis at power on */ + bool bod12_hysteresis; +#endif +}; + +/** + * \name Configuration and Initialization + * @{ + */ + +/** + * \brief Initializes an NVM controller configuration structure to defaults. + * + * Initializes a given NVM controller configuration structure to a set of + * known default values. This function should be called on all new + * instances of these configuration structures before being modified by the + * user application. + * + * The default configuration is as follows: + * \li Power reduction mode enabled after sleep mode until first NVM access + * \li Automatic page write mode disabled + * \li Number of FLASH wait states left unchanged + * + * \param[out] config Configuration structure to initialize to default values + * + */ +static inline void nvm_get_config_defaults( + struct nvm_config *const config) +{ + /* Sanity check the parameters */ + Assert(config); + + /* Write the default configuration for the NVM configuration */ + config->sleep_power_mode = NVM_SLEEP_POWER_MODE_WAKEONACCESS; + config->manual_page_write = true; + config->wait_states = NVMCTRL->CTRLB.bit.RWS; + config->disable_cache = false; +#if (SAMC20) || (SAMC21) + config->disable_rww_cache = false; +#endif + config->cache_readmode = NVM_CACHE_READMODE_NO_MISS_PENALTY; +} + +enum status_code nvm_set_config( + const struct nvm_config *const config); + +/** + * \brief Checks if the NVM controller is ready to accept a new command. + * + * Checks the NVM controller to determine if it is currently busy execution an + * operation, or ready for a new command. + * + * \return Busy state of the NVM controller. + * + * \retval true If the hardware module is ready for a new command + * \retval false If the hardware module is busy executing a command + * + */ +static inline bool nvm_is_ready(void) +{ + /* Get a pointer to the module hardware instance */ + Nvmctrl *const nvm_module = NVMCTRL; + + return nvm_module->INTFLAG.reg & NVMCTRL_INTFLAG_READY; +} + +/** @} */ + +/** + * \name NVM Access Management + * @{ + */ + +void nvm_get_parameters( + struct nvm_parameters *const parameters); + +enum status_code nvm_write_buffer( + const uint32_t destination_address, + const uint8_t *buffer, + uint16_t length); + +enum status_code nvm_read_buffer( + const uint32_t source_address, + uint8_t *const buffer, + uint16_t length); + +enum status_code nvm_update_buffer( + const uint32_t destination_address, + uint8_t *const buffer, + uint16_t offset, + uint16_t length); + +enum status_code nvm_erase_row( + const uint32_t row_address); + +enum status_code nvm_execute_command( + const enum nvm_command command, + const uint32_t address, + const uint32_t parameter); + +enum status_code nvm_get_fuses(struct nvm_fusebits *fusebits); +enum status_code nvm_set_fuses(struct nvm_fusebits *fb); + +bool nvm_is_page_locked(uint16_t page_number); + +/** + * \brief Retrieves the error code of the last issued NVM operation. + * + * Retrieves the error code from the last executed NVM operation. Once + * retrieved, any error state flags in the controller are cleared. + * + * \note The \ref nvm_is_ready() function is an exception. Thus, errors + * retrieved after running this function should be valid for the function + * executed before \ref nvm_is_ready(). + * + * \return Error caused by the last NVM operation. + * + * \retval NVM_ERROR_NONE No error occurred in the last NVM operation + * + * \retval NVM_ERROR_LOCK The last NVM operation attempted to access a locked + * region + * \retval NVM_ERROR_PROG An invalid NVM command was issued + */ +static inline enum nvm_error nvm_get_error(void) +{ + enum nvm_error ret_val; + + /* Get a pointer to the module hardware instance */ + Nvmctrl *const nvm_module = NVMCTRL; + + /* Mask out non-error bits */ + ret_val = (enum nvm_error)(nvm_module->STATUS.reg & NVM_ERRORS_MASK); + + /* Clear error flags */ + nvm_module->STATUS.reg = NVM_ERRORS_MASK; + + /* Return error code from the NVM controller */ + return ret_val; +} + +/** @} */ + +#ifdef __cplusplus +} +#endif + +/** @} */ + +/** + * \page asfdoc_sam0_nvm_extra Extra Information for NVM Driver + * + * \section asfdoc_sam0_nvm_extra_acronyms Acronyms + * The table below presents the acronyms used in this module: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
AcronymDescription
NVMNon-Volatile Memory
EEPROMElectrically Erasable Programmable Read-Only Memory
+ * + * + * \section asfdoc_sam0_nvm_extra_dependencies Dependencies + * This driver has the following dependencies: + * + * - None + * + * + * \section asfdoc_sam0_nvm_extra_errata Errata + * There are no errata related to this driver. + * + * + * \section asfdoc_sam0_nvm_extra_history Module History + * An overview of the module history is presented in the table below, with + * details on the enhancements and fixes made to the module since its first + * release. The current version of this corresponds to the newest version in + * the table. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Changelog
Removed BOD12 reference, removed nvm_set_fuses() API
Added functions to read/write fuse settings
Added support for NVM cache configuration
Updated initialization function to also enable the digital interface + * clock to the module if it is disabled
Initial Release
+ */ + +/** + * \page asfdoc_sam0_nvm_exqsg Examples for NVM Driver + * + * This is a list of the available Quick Start guides (QSGs) and example + * applications for \ref asfdoc_sam0_nvm_group. QSGs are simple examples with + * step-by-step instructions to configure and use this driver in a selection of + * use cases. Note that a QSG can be compiled as a standalone application or be + * added to the user application. + * + * - \subpage asfdoc_sam0_nvm_basic_use_case + * + * \page asfdoc_sam0_nvm_document_revision_history Document Revision History + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Doc. Rev.DateComments
42114E12/2015Added support for SAM L21/L22, SAM C21, SAM D09, SAMR30/R34 and SAM DA1
42114D12/2014Added support for SAM R21 and SAM D10/D11
42114C01/2014Added support for SAM D21
42114B06/2013Corrected documentation typos
42114A06/2013Initial document release
+ */ + +#endif /* NVM_H_INCLUDED */ diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/nvm/quick_start_basic/qs_nvm_basic.h b/src/boards/mcu/samr34/ASF/sam0/drivers/nvm/quick_start_basic/qs_nvm_basic.h new file mode 100644 index 000000000..2817c4c12 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/nvm/quick_start_basic/qs_nvm_basic.h @@ -0,0 +1,111 @@ +/** + * \file + * + * \brief SAM Non Volatile Memory Driver Quick Start + * + * Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ + +/** + * \page asfdoc_sam0_nvm_basic_use_case Quick Start Guide for NVM - Basic + * + * In this use case, the NVM module is configured for: + * \li Power reduction mode enabled after sleep mode until first NVM access + * \li Automatic page write commands issued to commit data as pages are written + * to the internal buffer + * \li Zero wait states when reading FLASH memory + * \li No memory space for the EEPROM + * \li No protected bootloader section + * + * This use case sets up the NVM controller to write a page of data to flash, + * and then read it back into the same buffer. + * + * \section asfdoc_sam0_nvm_basic_use_case_setup Setup + * + * \subsection asfdoc_sam0_nvm_basic_use_case_setup_prereq Prerequisites + * There are no special setup requirements for this use-case. + * + * \subsection asfdoc_sam0_nvm_basic_use_case_setup_code Code + * Copy-paste the following setup code to your user application: + * \snippet qs_nvm_basic.c setup + * + * Add to user application initialization (typically the start of \c main()): + * \snippet qs_nvm_basic.c setup_init + * + * \subsection asfdoc_sam0_nvm_basic_use_case_setup_flow Workflow + * -# Create an NVM module configuration struct, which can be filled + * out to adjust the configuration of the NVM controller. + * \snippet qs_nvm_basic.c setup_1 + * -# Initialize the NVM configuration struct with the module's default + * values. + * \snippet qs_nvm_basic.c setup_2 + * \note This should always be performed before using the configuration + * struct to ensure that all values are initialized to known default + * settings. + * -# Enable automatic page write mode. The new data will be written to NVM automaticly. + * \snippet qs_nvm_basic.c setup_3 + * \note If automatic page write mode is disabled, the data will not write to NVM + * until the NVM write command has been invoked. For safe use of the NVM module, + * disable automatic page write mode and use write command to commit data is + * recommended. + * + * -# Configure NVM controller with the created configuration struct settings. + * \snippet qs_nvm_basic.c setup_4 + * + * \section asfdoc_sam0_nvm_basic_use_case_main Use Case + * + * \subsection asfdoc_sam0_nvm_basic_use_case_main_code Code + * Copy-paste the following code to your user application: + * \snippet qs_nvm_basic.c main + * + * \subsection asfdoc_sam0_nvm_basic_use_case_main_flow Workflow + * -# Set up a buffer, one NVM page in size, to hold data to read or write into + * NVM memory. + * \snippet qs_nvm_basic.c main_1 + * -# Fill the buffer with a pattern of data. + * \snippet qs_nvm_basic.c main_2 + * -# Create a variable to hold the error status from the called NVM functions. + * \snippet qs_nvm_basic.c main_3 + * -# Erase a page of NVM data. As the NVM could be busy initializing or + * completing a previous operation, a loop is used to retry the command while + * the NVM controller is busy. + * \snippet qs_nvm_basic.c main_4 + * \note This must be performed before writing new data into an NVM page. + * + * -# Write the data buffer to the previously erased page of the NVM. + * \snippet qs_nvm_basic.c main_5 + * \note The new data will be written to NVM memory automatically, as the + * NVM controller is configured in automatic page write mode. + * + * -# Read back the written page of page from the NVM into the buffer. + * \snippet qs_nvm_basic.c main_6 + */ +/* + * Support and FAQ: visit Microchip Support + */ + diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/port/port.c b/src/boards/mcu/samr34/ASF/sam0/drivers/port/port.c new file mode 100644 index 000000000..87ef65af3 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/port/port.c @@ -0,0 +1,99 @@ +/** + * \file + * + * \brief SAM GPIO Port Driver + * + * Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#include + +/** + * \brief Writes a Port pin configuration to the hardware module. + * + * Writes out a given configuration of a Port pin configuration to the hardware + * module. + * + * \note If the pin direction is set as an output, the pull-up/pull-down input + * configuration setting is ignored. + * + * \param[in] gpio_pin Index of the GPIO pin to configure + * \param[in] config Configuration settings for the pin + */ +void port_pin_set_config( + const uint8_t gpio_pin, + const struct port_config *const config) +{ + /* Sanity check arguments */ + Assert(config); + + struct system_pinmux_config pinmux_config; + system_pinmux_get_config_defaults(&pinmux_config); + + pinmux_config.mux_position = SYSTEM_PINMUX_GPIO; + pinmux_config.direction = (enum system_pinmux_pin_dir)config->direction; + pinmux_config.input_pull = (enum system_pinmux_pin_pull)config->input_pull; + pinmux_config.powersave = config->powersave; + + system_pinmux_pin_set_config(gpio_pin, &pinmux_config); +} + +/** + * \brief Writes a Port group configuration group to the hardware module. + * + * Writes out a given configuration of a Port group configuration to the + * hardware module. + * + * \note If the pin direction is set as an output, the pull-up/pull-down input + * configuration setting is ignored. + * + * \param[out] port Base of the PORT module to write to + * \param[in] mask Mask of the port pin(s) to configure + * \param[in] config Configuration settings for the pin group + */ +void port_group_set_config( + PortGroup *const port, + const uint32_t mask, + const struct port_config *const config) +{ + /* Sanity check arguments */ + Assert(port); + Assert(config); + + struct system_pinmux_config pinmux_config; + system_pinmux_get_config_defaults(&pinmux_config); + + pinmux_config.mux_position = SYSTEM_PINMUX_GPIO; + pinmux_config.direction = (enum system_pinmux_pin_dir)config->direction; + pinmux_config.input_pull = (enum system_pinmux_pin_pull)config->input_pull; + pinmux_config.powersave = config->powersave; + + system_pinmux_group_set_config(port, mask, &pinmux_config); +} diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/port/port.h b/src/boards/mcu/samr34/ASF/sam0/drivers/port/port.h new file mode 100644 index 000000000..9033e7c7f --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/port/port.h @@ -0,0 +1,785 @@ +/** + * \file + * + * \brief SAM GPIO Port Driver + * + * Copyright (c) 2012-2020 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#ifndef PORT_H_INCLUDED +#define PORT_H_INCLUDED + +/** + * \defgroup asfdoc_sam0_port_group SAM Port (PORT) Driver + * + * This driver for Atmel® | SMART ARM®-based microcontrollers provides + * an interface for the configuration and management of the device's General + * Purpose Input/Output (GPIO) pin functionality, for manual pin state reading + * and writing. + * + * The following peripheral is used by this module: + * - PORT (GPIO Management) + * + * The following devices can use this module: + * - Atmel | SMART SAM D20/D21 + * - Atmel | SMART SAM R21 + * - Atmel | SMART SAM D09/D10/D11 + * - Atmel | SMART SAM L21/L22 + * - Atmel | SMART SAM DA1 + * - Atmel | SMART SAM C20/C21 + * - Atmel | SMART SAM HA1 + * - Atmel | SMART SAM R30 + * - Atmel | SMART SAM R34 + * - Atmel | SMART SAM R35 + * + * The outline of this documentation is as follows: + * - \ref asfdoc_sam0_port_prerequisites + * - \ref asfdoc_sam0_port_module_overview + * - \ref asfdoc_sam0_port_special_considerations + * - \ref asfdoc_sam0_port_extra_info + * - \ref asfdoc_sam0_port_examples + * - \ref asfdoc_sam0_port_api_overview + * + * + * \section asfdoc_sam0_port_prerequisites Prerequisites + * + * There are no prerequisites for this module. + * + * + * \section asfdoc_sam0_port_module_overview Module Overview + * + * The device GPIO (PORT) module provides an interface between the user + * application logic and external hardware peripherals, when general pin state + * manipulation is required. This driver provides an easy-to-use interface to + * the physical pin input samplers and output drivers, so that pins can be read + * from or written to for general purpose external hardware control. + * + * \subsection asfdoc_sam0_port_features Driver Feature Macro Definition + * + * + * + * + * + * + * + * + * + *
Driver Feature MacroSupported devices
FEATURE_PORT_INPUT_EVENTSAM L21/L22/C20/C21/R30/R34/R35
+ * \note The specific features are only available in the driver when the + * selected device supports those features. + * + * \subsection asfdoc_sam0_port_module_overview_pin_numbering Physical and Logical GPIO Pins + * SAM devices use two naming conventions for the I/O pins in the device; one + * physical and one logical. Each physical pin on a device package is assigned + * both a physical port and pin identifier (e.g. "PORTA.0") as well as a + * monotonically incrementing logical GPIO number (e.g. "GPIO0"). While the + * former is used to map physical pins to their physical internal device module + * counterparts, for simplicity the design of this driver uses the logical GPIO + * numbers instead. + * + * \subsection asfdoc_sam0_port_module_overview_physical Physical Connection + * + * \ref asfdoc_sam0_port_module_int_connections "The diagram below" shows how + * this module is interconnected within the device. + * + * \anchor asfdoc_sam0_port_module_int_connections + * \dot + * digraph overview { + * node [label="Port Pad" shape=square] pad; + * + * subgraph driver { + * node [label="Peripheral MUX" shape=trapezium] pinmux; + * node [label="GPIO Module" shape=ellipse] gpio; + * node [label="Other Peripheral Modules" shape=ellipse style=filled fillcolor=lightgray] peripherals; + * } + * + * pinmux -> gpio; + * pad -> pinmux; + * pinmux -> peripherals; + * } + * \enddot + * + * + * \section asfdoc_sam0_port_special_considerations Special Considerations + * + * The SAM port pin input sampler can be disabled when the pin is configured + * in pure output mode to save power; reading the pin state of a pin configured + * in output-only mode will read the logical output state that was last set. + * + * \section asfdoc_sam0_port_extra_info Extra Information + * + * For extra information, see \ref asfdoc_sam0_port_extra. This includes: + * - \ref asfdoc_sam0_port_extra_acronyms + * - \ref asfdoc_sam0_port_extra_dependencies + * - \ref asfdoc_sam0_port_extra_errata + * - \ref asfdoc_sam0_port_extra_history + * + * + * \section asfdoc_sam0_port_examples Examples + * + * For a list of examples related to this driver, see + * \ref asfdoc_sam0_port_exqsg. + * + * + * \section asfdoc_sam0_port_api_overview API Overview + * @{ + */ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \name Driver Feature Definition + * Define port features set according to different device family. + * @{ +*/ +#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) || defined(__DOXYGEN__) +/** Event input control feature support for PORT group. */ +# define FEATURE_PORT_INPUT_EVENT +#endif +/*@}*/ + +/** \name PORT Alias Macros + * @{ + */ + +/** Convenience definition for GPIO module group A on the device (if + * available). */ +#if (PORT_GROUPS > 0) || defined(__DOXYGEN__) +# define PORTA PORT->Group[0] +#endif + +#if (PORT_GROUPS > 1) || defined(__DOXYGEN__) +/** Convenience definition for GPIO module group B on the device (if + * available). */ +# define PORTB PORT->Group[1] +#endif + +#if (PORT_GROUPS > 2) || defined(__DOXYGEN__) +/** Convenience definition for GPIO module group C on the device (if + * available). */ +# define PORTC PORT->Group[2] +#endif + +#if (PORT_GROUPS > 3) || defined(__DOXYGEN__) +/** Convenience definition for GPIO module group D on the device (if + * available). */ +# define PORTD PORT->Group[3] +#endif + +/** @} */ + +/** + * \brief Port pin direction configuration enum. + * + * Enum for the possible pin direction settings of the port pin configuration + * structure, to indicate the direction the pin should use. + */ +enum port_pin_dir { + /** The pin's input buffer should be enabled, so that the pin state can + * be read */ + PORT_PIN_DIR_INPUT = SYSTEM_PINMUX_PIN_DIR_INPUT, + /** The pin's output buffer should be enabled, so that the pin state can + * be set */ + PORT_PIN_DIR_OUTPUT = SYSTEM_PINMUX_PIN_DIR_OUTPUT, + /** The pin's output and input buffers should be enabled, so that the pin + * state can be set and read back */ + PORT_PIN_DIR_OUTPUT_WTH_READBACK = SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK, +}; + +/** + * \brief Port pin input pull configuration enum. + * + * Enum for the possible pin pull settings of the port pin configuration + * structure, to indicate the type of logic level pull the pin should use. + */ +enum port_pin_pull { + /** No logical pull should be applied to the pin */ + PORT_PIN_PULL_NONE = SYSTEM_PINMUX_PIN_PULL_NONE, + /** Pin should be pulled up when idle */ + PORT_PIN_PULL_UP = SYSTEM_PINMUX_PIN_PULL_UP, + /** Pin should be pulled down when idle */ + PORT_PIN_PULL_DOWN = SYSTEM_PINMUX_PIN_PULL_DOWN, +}; + +#ifdef FEATURE_PORT_INPUT_EVENT +/** + * \brief Port input event action. + * + * List of port input events action on pin. + */ +enum port_input_event_action { + /** Event out to pin */ + PORT_INPUT_EVENT_ACTION_OUT = 0, + /** Set output register of pin on event */ + PORT_INPUT_EVENT_ACTION_SET, + /** Clear output register pin on event */ + PORT_INPUT_EVENT_ACTION_CLR, + /** Toggle output register pin on event */ + PORT_INPUT_EVENT_ACTION_TGL, +}; + +/** + * \brief Port input event. + * + * List of port input events. + */ +enum port_input_event{ + /** Port input event 0 */ + PORT_INPUT_EVENT_0 = 0, + /** Port input event 1 */ + PORT_INPUT_EVENT_1 = 1, + /** Port input event 2 */ + PORT_INPUT_EVENT_2 = 2, + /** Port input event 3 */ + PORT_INPUT_EVENT_3 = 3, +}; + +/** + * \brief Port input event configuration structure. + * + * Configuration structure for a port input event. + */ +struct port_input_event_config{ + /** Port input event action */ + enum port_input_event_action action; + /** GPIO pin */ + uint8_t gpio_pin; +}; +#endif + +/** + * \brief Port pin configuration structure. + * + * Configuration structure for a port pin instance. This structure should be + * initialized by the \ref port_get_config_defaults() function before being + * modified by the user application. + */ +struct port_config { + /** Port buffer input/output direction */ + enum port_pin_dir direction; + + /** Port pull-up/pull-down for input pins */ + enum port_pin_pull input_pull; + + /** Enable lowest possible powerstate on the pin + * + * \note All other configurations will be ignored, the pin will be disabled. + */ + bool powersave; +}; + +/** \name State Reading/Writing (Physical Group Orientated) + * @{ + */ + +/** + * \brief Retrieves the PORT module group instance from a given GPIO pin number. + * + * Retrieves the PORT module group instance associated with a given logical + * GPIO pin number. + * + * \param[in] gpio_pin Index of the GPIO pin to convert + * + * \return Base address of the associated PORT module. + */ +static inline PortGroup* port_get_group_from_gpio_pin( + const uint8_t gpio_pin) +{ + return system_pinmux_get_group_from_gpio_pin(gpio_pin); +} + +/** + * \brief Retrieves the state of a group of port pins that are configured as inputs. + * + * Reads the current logic level of a port module's pins and returns the + * current levels as a bitmask. + * + * \param[in] port Base of the PORT module to read from + * \param[in] mask Mask of the port pin(s) to read + * + * \return Status of the port pin(s) input buffers. + */ +static inline uint32_t port_group_get_input_level( + const PortGroup *const port, + const uint32_t mask) +{ + /* Sanity check arguments */ + Assert(port); + + return (port->IN.reg & mask); +} + +/** + * \brief Retrieves the state of a group of port pins that are configured as outputs. + * + * Reads the current logical output level of a port module's pins and returns + * the current levels as a bitmask. + * + * \param[in] port Base of the PORT module to read from + * \param[in] mask Mask of the port pin(s) to read + * + * \return Status of the port pin(s) output buffers. + */ +static inline uint32_t port_group_get_output_level( + const PortGroup *const port, + const uint32_t mask) +{ + /* Sanity check arguments */ + Assert(port); + + return (port->OUT.reg & mask); +} + +/** + * \brief Sets the state of a group of port pins that are configured as outputs. + * + * Sets the current output level of a port module's pins to a given logic + * level. + * + * \param[out] port Base of the PORT module to write to + * \param[in] mask Mask of the port pin(s) to change + * \param[in] level_mask Mask of the port level(s) to set + */ +static inline void port_group_set_output_level( + PortGroup *const port, + const uint32_t mask, + const uint32_t level_mask) +{ + /* Sanity check arguments */ + Assert(port); + + port->OUTSET.reg = (mask & level_mask); + port->OUTCLR.reg = (mask & ~level_mask); +} + +/** + * \brief Toggles the state of a group of port pins that are configured as an outputs. + * + * Toggles the current output levels of a port module's pins. + * + * \param[out] port Base of the PORT module to write to + * \param[in] mask Mask of the port pin(s) to toggle + */ +static inline void port_group_toggle_output_level( + PortGroup *const port, + const uint32_t mask) +{ + /* Sanity check arguments */ + Assert(port); + + port->OUTTGL.reg = mask; +} + +/** @} */ + +/** \name Configuration and Initialization + * @{ + */ + +/** + * \brief Initializes a Port pin/group configuration structure to defaults. + * + * Initializes a given Port pin/group configuration structure to a set of + * known default values. This function should be called on all new + * instances of these configuration structures before being modified by the + * user application. + * + * The default configuration is as follows: + * \li Input mode with internal pull-up enabled + * + * \param[out] config Configuration structure to initialize to default values + */ +static inline void port_get_config_defaults( + struct port_config *const config) +{ + /* Sanity check arguments */ + Assert(config); + + /* Default configuration values */ + config->direction = PORT_PIN_DIR_INPUT; + config->input_pull = PORT_PIN_PULL_UP; + config->powersave = false; +} + +void port_pin_set_config( + const uint8_t gpio_pin, + const struct port_config *const config); + +void port_group_set_config( + PortGroup *const port, + const uint32_t mask, + const struct port_config *const config); + +/** @} */ + +/** \name State Reading/Writing (Logical Pin Orientated) + * @{ + */ + +/** + * \brief Retrieves the state of a port pin that is configured as an input. + * + * Reads the current logic level of a port pin and returns the current + * level as a Boolean value. + * + * \param[in] gpio_pin Index of the GPIO pin to read + * + * \return Status of the port pin's input buffer. + */ +static inline bool port_pin_get_input_level( + const uint8_t gpio_pin) +{ + PortGroup *const port_base = port_get_group_from_gpio_pin(gpio_pin); + uint32_t pin_mask = (1UL << (gpio_pin % 32)); + + return (port_base->IN.reg & pin_mask); +} + +/** + * \brief Retrieves the state of a port pin that is configured as an output. + * + * Reads the current logical output level of a port pin and returns the current + * level as a Boolean value. + * + * \param[in] gpio_pin Index of the GPIO pin to read + * + * \return Status of the port pin's output buffer. + */ +static inline bool port_pin_get_output_level( + const uint8_t gpio_pin) +{ + PortGroup *const port_base = port_get_group_from_gpio_pin(gpio_pin); + uint32_t pin_mask = (1UL << (gpio_pin % 32)); + + return (port_base->OUT.reg & pin_mask); +} + +/** + * \brief Sets the state of a port pin that is configured as an output. + * + * Sets the current output level of a port pin to a given logic level. + * + * \param[in] gpio_pin Index of the GPIO pin to write to + * \param[in] level Logical level to set the given pin to + */ +static inline void port_pin_set_output_level( + const uint8_t gpio_pin, + const bool level) +{ + PortGroup *const port_base = port_get_group_from_gpio_pin(gpio_pin); + uint32_t pin_mask = (1UL << (gpio_pin % 32)); + + /* Set the pin to high or low atomically based on the requested level */ + if (level) { + port_base->OUTSET.reg = pin_mask; + } else { + port_base->OUTCLR.reg = pin_mask; + } +} + +/** + * \brief Toggles the state of a port pin that is configured as an output. + * + * Toggles the current output level of a port pin. + * + * \param[in] gpio_pin Index of the GPIO pin to toggle + */ +static inline void port_pin_toggle_output_level( + const uint8_t gpio_pin) +{ + PortGroup *const port_base = port_get_group_from_gpio_pin(gpio_pin); + uint32_t pin_mask = (1UL << (gpio_pin % 32)); + + /* Toggle pin output level */ + port_base->OUTTGL.reg = pin_mask; +} + +/** @} */ + +#ifdef FEATURE_PORT_INPUT_EVENT + +/** \name Port Input Event + * @{ + */ + +/** + * \brief Enable the port event input. + * + * Enable the port event input with the given pin and event. + * + * \param[in] gpio_pin Index of the GPIO pin + * \param[in] n Port input event + * + * \retval STATUS_ERR_INVALID_ARG Invalid parameter + * \retval STATUS_OK Successfully + */ +static inline enum status_code port_enable_input_event( + const uint8_t gpio_pin, + const enum port_input_event n) +{ + PortGroup *const port_base = port_get_group_from_gpio_pin(gpio_pin); + switch (n) { + case PORT_INPUT_EVENT_0: + port_base->EVCTRL.reg |= PORT_EVCTRL_PORTEI0; + break; + case PORT_INPUT_EVENT_1: + port_base->EVCTRL.reg |= PORT_EVCTRL_PORTEI1; + break; + case PORT_INPUT_EVENT_2: + port_base->EVCTRL.reg |= PORT_EVCTRL_PORTEI2; + break; + case PORT_INPUT_EVENT_3: + port_base->EVCTRL.reg |= PORT_EVCTRL_PORTEI3; + break; + default: + Assert(false); + return STATUS_ERR_INVALID_ARG; + } + return STATUS_OK; +} + +/** + * \brief Disable the port event input. + * + * Disable the port event input with the given pin and event. + * + * \param[in] gpio_pin Index of the GPIO pin + * \param[in] gpio_pin Port input event + * + * \retval STATUS_ERR_INVALID_ARG Invalid parameter + * \retval STATUS_OK Successfully + */ +static inline enum status_code port_disable_input_event( + const uint8_t gpio_pin, + const enum port_input_event n) +{ + PortGroup *const port_base = port_get_group_from_gpio_pin(gpio_pin); + switch (n) { + case PORT_INPUT_EVENT_0: + port_base->EVCTRL.reg &= ~PORT_EVCTRL_PORTEI0; + break; + case PORT_INPUT_EVENT_1: + port_base->EVCTRL.reg &= ~PORT_EVCTRL_PORTEI1; + break; + case PORT_INPUT_EVENT_2: + port_base->EVCTRL.reg &= ~PORT_EVCTRL_PORTEI2; + break; + case PORT_INPUT_EVENT_3: + port_base->EVCTRL.reg &= ~PORT_EVCTRL_PORTEI3; + break; + default: + Assert(false); + return STATUS_ERR_INVALID_ARG; + } + return STATUS_OK; +} + +/** + * \brief Retrieve the default configuration for port input event. + * + * Fills a configuration structure with the default configuration for port input event: + * - Event output to pin + * - Event action to be executed on PIN 0 + * + * \param[out] config Configuration structure to fill with default values + */ +static inline void port_input_event_get_config_defaults( + struct port_input_event_config *const config) +{ + Assert(config); + config->action = PORT_INPUT_EVENT_ACTION_OUT; + config->gpio_pin = 0; +} + +/** + * \brief Configure port input event. + * + * Configures port input event with the given configuration settings. + * + * \param[in] config Port input even configuration structure containing the new config + * + * \retval STATUS_ERR_INVALID_ARG Invalid parameter + * \retval STATUS_OK Successfully + */ + +static inline enum status_code port_input_event_set_config( + const enum port_input_event n, + struct port_input_event_config *const config) +{ + Assert(config); + PortGroup *const port_base = port_get_group_from_gpio_pin(config->gpio_pin); + uint8_t pin_index = config->gpio_pin % 32; + struct port_config pin_conf; + + port_get_config_defaults(&pin_conf); + /* Configure the GPIO pin as outputs*/ + pin_conf.direction = PORT_PIN_DIR_OUTPUT; + port_pin_set_config(config->gpio_pin, &pin_conf); + + switch (n) { + case PORT_INPUT_EVENT_0: + port_base->EVCTRL.reg |= PORT_EVCTRL_EVACT0(config->action) + | PORT_EVCTRL_PID0(pin_index); + break; + case PORT_INPUT_EVENT_1: + port_base->EVCTRL.reg |= PORT_EVCTRL_EVACT1(config->action) + | PORT_EVCTRL_PID1(pin_index); + break; + case PORT_INPUT_EVENT_2: + port_base->EVCTRL.reg |= PORT_EVCTRL_EVACT2(config->action) + | PORT_EVCTRL_PID2(pin_index); + break; + case PORT_INPUT_EVENT_3: + port_base->EVCTRL.reg |= PORT_EVCTRL_EVACT3(config->action) + | PORT_EVCTRL_PID3(pin_index); + break; + default: + Assert(false); + return STATUS_ERR_INVALID_ARG; + } + return STATUS_OK; +} + +/** @} */ + +#endif + +#ifdef __cplusplus +} +#endif + +/** @} */ + +/** + * \page asfdoc_sam0_port_extra Extra Information for PORT Driver + * + * \section asfdoc_sam0_port_extra_acronyms Acronyms + * Below is a table listing the acronyms used in this module, along with their + * intended meanings. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
AcronymDescription
GPIOGeneral Purpose Input/Output
MUXMultiplexer
+ * + * + * \section asfdoc_sam0_port_extra_dependencies Dependencies + * This driver has the following dependencies: + * + * - \ref asfdoc_sam0_system_pinmux_group "System Pin Multiplexer Driver" + * + * + * \section asfdoc_sam0_port_extra_errata Errata + * There are no errata related to this driver. + * + * + * \section asfdoc_sam0_port_extra_history Module History + * An overview of the module history is presented in the table below, with + * details on the enhancements and fixes made to the module since its first + * release. The current version of this corresponds to the newest version in + * the table. + * + * + * + * + * + * + * + * + * + * + * + *
Changelog
Added input event feature
Initial release
+ */ + +/** + * \page asfdoc_sam0_port_exqsg Examples for PORT Driver + * + * This is a list of the available Quick Start guides (QSGs) and example + * applications for \ref asfdoc_sam0_port_group. QSGs are simple examples with + * step-by-step instructions to configure and use this driver in a selection of + * use cases. Note that a QSG can be compiled as a standalone application or be + * added to the user application. + * + * - \subpage asfdoc_sam0_port_basic_use_case + * + * \page asfdoc_sam0_port_document_revision_history Document Revision History + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Doc. Rev. + * Date + * Comments + *
42113E12/2015Added input event feature. + * Added support for SAM L21/L22, SAM C21, SAM D09, SAMR30/R34 and SAM DA1.
42113D12/2014Added support for SAM R21 and SAM D10/D11
42113C01/2014Added support for SAM D21
42113B06/2013Corrected documentation typos
42113A06/2013Initial document release
+ */ + +#endif diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/port/quick_start/qs_port_basic.h b/src/boards/mcu/samr34/ASF/sam0/drivers/port/quick_start/qs_port_basic.h new file mode 100644 index 000000000..b171c6955 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/port/quick_start/qs_port_basic.h @@ -0,0 +1,98 @@ +/** + * \file + * + * \brief SAM GPIO Port Driver Quick Start + * + * Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ + +/** + * \page asfdoc_sam0_port_basic_use_case Quick Start Guide for PORT - Basic + * + * In this use case, the PORT module is configured for: + * \li One pin in input mode, with pull-up enabled + * \li One pin in output mode + * + * This use case sets up the PORT to read the current state of a GPIO pin set as + * an input, and mirrors the opposite logical state on a pin configured as an + * output. + * + * \section asfdoc_sam0_port_basic_use_case_setup Setup + * + * \subsection asfdoc_sam0_port_basic_use_case_setup_prereq Prerequisites + * There are no special setup requirements for this use-case. + * + * \subsection asfdoc_sam0_port_basic_use_case_setup_code Code + * Copy-paste the following setup code to your user application: + * \snippet qs_port_basic.c setup + * + * Add to user application initialization (typically the start of \c main()): + * \snippet qs_port_basic.c setup_init + * + * \subsection asfdoc_sam0_port_basic_use_case_setup_flow Workflow + * -# Create a PORT module pin configuration struct, which can be filled out to + * adjust the configuration of a single port pin. + * \snippet qs_port_basic.c setup_1 + * -# Initialize the pin configuration struct with the module's default values. + * \snippet qs_port_basic.c setup_2 + * \note This should always be performed before using the configuration + * struct to ensure that all values are initialized to known default + * settings. + * + * -# Adjust the configuration struct to request an input pin. + * \snippet qs_port_basic.c setup_3 + * -# Configure push button pin with the initialized pin configuration struct, to enable + * the input sampler on the pin. + * \snippet qs_port_basic.c setup_4 + * -# Adjust the configuration struct to request an output pin. + * \snippet qs_port_basic.c setup_5 + * \note The existing configuration struct may be re-used, as long as any + * values that have been altered from the default settings are taken + * into account by the user application. + * + * -# Configure LED pin with the initialized pin configuration struct, to enable + * the output driver on the pin. + * \snippet qs_port_basic.c setup_6 + * + * \section asfdoc_sam0_port_basic_use_case_use_main Use Case + * + * \subsection asfdoc_sam0_port_basic_use_case_code Code + * Copy-paste the following code to your user application: + * \snippet qs_port_basic.c main + * + * \subsection asfdoc_sam0_port_basic_use_case_flow Workflow + * -# Read in the current input sampler state of push button pin, which has been + * configured as an input in the use-case setup code. + * \snippet qs_port_basic.c main_1 + * -# Write the inverted pin level state to LED pin, which has been configured as + * an output in the use-case setup code. + * \snippet qs_port_basic.c main_2 + */ +/* + * Support and FAQ: visit Microchip Support + */ diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/rtc/rtc_count.h b/src/boards/mcu/samr34/ASF/sam0/drivers/rtc/rtc_count.h new file mode 100644 index 000000000..b74077394 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/rtc/rtc_count.h @@ -0,0 +1,1293 @@ +/** + * \file + * + * \brief SAM RTC Driver (Count Mode) + * + * Copyright (c) 2012-2020 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#ifndef RTC_COUNT_H_INCLUDED +#define RTC_COUNT_H_INCLUDED + +/** + * \defgroup asfdoc_sam0_rtc_count_group SAM RTC Count (RTC COUNT) Driver + * + * This driver for Atmel® | SMART ARM®-based microcontrollers provides + * an interface for the configuration and management of the device's Real Time + * Clock functionality in Count operating mode, for the configuration and + * retrieval of the current RTC counter value. The following driver API modes + * are covered by this manual: + * + * - Polled APIs + * \if RTC_COUNT_CALLBACK_MODE + * - Callback APIs + * \endif + * + * The following peripheral is used by this module: + * - RTC (Real Time Clock) + * + * The following devices can use this module: + * - Atmel | SMART SAM D20/D21 + * - Atmel | SMART SAM R21 + * - Atmel | SMART SAM D09/D10/D11 + * - Atmel | SMART SAM L21/L22 + * - Atmel | SMART SAM DA1 + * - Atmel | SMART SAM C20/C21 + * - Atmel | SMART SAM HA1 + * - Atmel | SMART SAM R30 + * - Atmel | SMART SAM R34 + * - Atmel | SMART SAM R35 + * + * The outline of this documentation is as follows: + * - \ref asfdoc_sam0_rtc_count_prerequisites + * - \ref asfdoc_sam0_rtc_count_module_overview + * - \ref asfdoc_sam0_rtc_count_special_considerations + * - \ref asfdoc_sam0_rtc_count_extra_info + * - \ref asfdoc_sam0_rtc_count_examples + * - \ref asfdoc_sam0_rtc_count_api_overview + * + * + * \section asfdoc_sam0_rtc_count_prerequisites Prerequisites + * + * There are no prerequisites for this module. + * + * + * \section asfdoc_sam0_rtc_count_module_overview Module Overview + * + * The RTC module in the SAM devices is a 32-bit counter, with a 10-bit + * programmable prescaler. Typically, the RTC clock is run continuously, + * including in the device's low-power sleep modes, to track the current time + * and date information. The RTC can be used as a source to wake up the system + * at a scheduled time or periodically using the alarm functions. + * + * In this driver, the RTC is operated in Count mode. This allows for an + * easy integration of an asynchronous counter into a user application, which is + * capable of operating while the device is in sleep mode. + * + * Whilst operating in Count mode, the RTC features: + * - 16-bit counter mode + * - Selectable counter period + * - Up to six configurable compare values + * - 32-bit counter mode + * - Clear counter value on match + * - Up to four configurable compare values + * + * \subsection asfdoc_sam0_rtc_count_features Driver Feature Macro Definition + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Driver Feature MacroSupported devices
FEATURE_RTC_PERIODIC_INTSAM L21/L22/C20/C21/R30
FEATURE_RTC_PRESCALER_OFFSAM L21/L22/C20/C21/R30
FEATURE_RTC_CLOCK_SELECTIONSAM L21/L22/C20/C21/R30
FEATURE_RTC_GENERAL_PURPOSE_REGSAM L21/L22/R30
FEATURE_RTC_CONTINUOUSLY_UPDATEDSAM D20, SAM D21, SAM R21, SAM D10, SAM D11, SAM DA1, SAM HA1
FEATURE_RTC_TAMPER_DETECTIONSAM L22
+ * \note The specific features are only available in the driver when the + * selected device supports those features. + * + * \section asfdoc_sam0_rtc_count_module_overview_compares Compare and Overflow + * The RTC can be used with up to 4/6 compare values (depending on selected + * operation mode). These compare values will trigger on match with the current + * RTC counter value, and can be set up to trigger an interrupt, event, or both. + * The RTC can also be configured to clear the counter value on compare match + * in 32-bit mode, resetting the count value back to zero. + * + * If the RTC is operated without the Clear on Match option enabled, or in + * 16-bit mode, the RTC counter value will instead be cleared on overflow once + * the maximum count value has been reached: + * + * \f[ COUNT_{MAX} = 2^{32}-1 \f] for 32-bit counter mode, and + * \f[ COUNT_{MAX} = 2^{16}-1 \f] for 16-bit counter mode. + * + * When running in 16-bit mode, the overflow value is selectable with a period + * value. The counter overflow will then occur when the counter value reaches + * the specified period value. + * + * \subsection asfdoc_sam0_rtc_count_module_overview_periodic Periodic Events + * The RTC can generate events at periodic intervals, allowing for direct + * peripheral actions without CPU intervention. The periodic events can be + * generated on the upper eight bits of the RTC prescaler, and will be generated on + * the rising edge transition of the specified bit. The resulting periodic + * frequency can be calculated by the following formula: + * + * \f[ f_{PERIODIC}=\frac{f_{ASY}}{2^{n+3}} \f] + * + * Where \f$f_{ASY}\f$ refers to the \e asynchronous clock is set up in the RTC + * module configuration. The \b n parameter is the event source generator index + * of the RTC module. If the asynchronous clock is operated at the recommended + * frequency of 1KHz, the formula results in the values shown in + * \ref asfdoc_sam0_rtc_count_module_rtc_hz "the table below". + * + * \anchor asfdoc_sam0_rtc_count_module_rtc_hz + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
RTC Event Frequencies for Each Prescaler Bit Using a 1KHz Clock
n Periodic event
7 1Hz
6 2Hz
5 4Hz
4 8Hz
3 16Hz
2 32Hz
1 64Hz
0 128Hz
+ * + * \note The connection of events between modules requires the use of the + * \ref asfdoc_sam0_events_group "SAM Event System (EVENTS) Driver" + * to route output event of one module to the the input event of another. + * For more information on event routing, refer to the event driver + * documentation. + * + * \subsection asfdoc_sam0_rtc_count_module_overview_correction Digital Frequency Correction + * The RTC module contains Digital Frequency Correction logic to compensate for + * inaccurate source clock frequencies which would otherwise result in skewed + * time measurements. The correction scheme requires that at least two bits + * in the RTC module prescaler are reserved by the correction logic. As a + * result of this implementation, frequency correction is only available when + * the RTC is running from a 1Hz reference clock. + * + * The correction procedure is implemented by subtracting or adding a single + * cycle from the RTC prescaler every 1024 RTC GCLK cycles. The adjustment is + * applied the specified number of time (maximum 127) over 976 of these periods. The + * corresponding correction in PPM will be given by: + * + * \f[ Correction(PPM) = \frac{VALUE}{999424}10^6 \f] + * + * The RTC clock will tick faster if provided with a positive correction value, + * and slower when given a negative correction value. + * + * + * \subsection asfdoc_sam0_rtc_count_module_overview_tamper_detect RTC Tamper Detect + * see \ref asfdoc_sam0_rtc_tamper_detect + * + * \section asfdoc_sam0_rtc_count_special_considerations Special Considerations + * + * \subsection asfdoc_sam0_rtc_count_special_considerations_clock Clock Setup + * \subsubsection asfdoc_sam0_rtc_count_clock_samd_r SAM D20/D21/R21/D10/D11/DA1/HA1 Clock Setup + * The RTC is typically clocked by a specialized GCLK generator that has a + * smaller prescaler than the others. By default the RTC clock is on, selected + * to use the internal 32KHz RC-oscillator with a prescaler of 32, giving a + * resulting clock frequency of 1KHz to the RTC. When the internal RTC + * prescaler is set to 1024, this yields an end-frequency of 1Hz. + * + * The implementer also has the option to set other end-frequencies. + * \ref asfdoc_sam0_rtc_count_rtc_out_freq "The table below" lists the + * available RTC frequencies for each possible GCLK and RTC input prescaler + * options. + * + * \anchor asfdoc_sam0_rtc_count_rtc_out_freq + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
RTC Output Frequencies from Allowable Input Clocks
End-frequencyGCLK prescalerRTC prescaler
32KHz11
1KHz321
1Hz321024
+ * + * The overall RTC module clocking scheme is shown in + * \ref asfdoc_sam0_rtc_count_rtc_clock_fig "the figure below". + * + * \anchor asfdoc_sam0_rtc_count_rtc_clock_fig + * \dot + * digraph clocking_scheme { + * rankdir=LR; + * GCLK [shape="record", label=" GCLK | RTC_GCLK", + * bgcolor="lightgray", style="filled"]; + * RTCPRE [shape="record" label=" RTC | RTC PRESCALER"]; + * RTC [shape="record", label=" RTC | RTC CLOCK"]; + * + * GCLK:f1 -> RTCPRE:f1; + * RTCPRE:f1 -> RTC:f1; + * } + * \enddot + * + * \subsubsection asfdoc_sam0_rtc_count_clock_saml SAM L21/C20/C21/R30 Clock Setup + * The RTC clock can be selected from OSC32K, XOSC32K, or OSCULP32K, and a 32KHz + * or 1KHz oscillator clock frequency is required. This clock must be + * configured and enabled in the 32KHz oscillator controller before using the RTC. + * + * The table below lists the available RTC clock \ref asfdoc_sam0_rtc_count_rtc_clk. + * + * \anchor asfdoc_sam0_rtc_count_rtc_clk + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
RTC Clocks Source
RTC clock frequencyClock sourceDescription
1.024KHzULP1K1.024KHz from 32KHz internal ULP oscillator
32.768KHzULP32K32.768KHz from 32KHz internal ULP oscillator
1.024KHzOSC1K1.024KHz from 32KHz internal oscillator
32.768KHzOSC32K32.768KHz from 32KHz internal oscillator
1.024KHzXOSC1K1.024KHz from 32KHz internal oscillator
32.768KHzXOSC32K32.768KHz from 32KHz external crystal oscillator
+ * + * \section asfdoc_sam0_rtc_count_extra_info Extra Information + * + * For extra information, see \ref asfdoc_sam0_rtc_count_extra. This includes: + * - \ref asfdoc_sam0_rtc_count_extra_acronyms + * - \ref asfdoc_sam0_rtc_count_extra_dependencies + * - \ref asfdoc_sam0_rtc_count_extra_errata + * - \ref asfdoc_sam0_rtc_count_extra_history + * + * + * \section asfdoc_sam0_rtc_count_examples Examples + * + * For a list of examples related to this driver, see + * \ref asfdoc_sam0_rtc_count_exqsg. + * + * + * \section asfdoc_sam0_rtc_count_api_overview API Overview + * @{ + */ + +#include +#include + +#if RTC_COUNT_ASYNC == true +# include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \name Driver Feature Definition + * + * Define port features set according to different device family. + * @{ +*/ +#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) || defined(__DOXYGEN__) +/** RTC periodic interval interrupt. */ +# define FEATURE_RTC_PERIODIC_INT +/** RTC prescaler is off. */ +# define FEATURE_RTC_PRESCALER_OFF +/** RTC clock selection. */ +# define FEATURE_RTC_CLOCK_SELECTION +# if !(SAMC20) && !(SAMC21) +/** General purpose registers. */ +# define FEATURE_RTC_GENERAL_PURPOSE_REG +# endif +#else +/** RTC continuously updated. */ +# define FEATURE_RTC_CONTINUOUSLY_UPDATED +#endif + +#if (SAML22) || defined(__DOXYGEN__) +/** RTC tamper detection. */ +# define FEATURE_RTC_TAMPER_DETECTION +#endif + +/*@}*/ + +#ifdef FEATURE_RTC_CLOCK_SELECTION +/** + * \brief Available clock source for RTC. + * RTC clock source. + */ +enum rtc_clock_sel { + /** 1.024KHz from 32KHz internal ULP oscillator */ + RTC_CLOCK_SELECTION_ULP1K = OSC32KCTRL_RTCCTRL_RTCSEL_ULP1K_Val, + /** 32.768KHz from 32KHz internal ULP oscillator */ + RTC_CLOCK_SELECTION_ULP32K = OSC32KCTRL_RTCCTRL_RTCSEL_ULP32K_Val, +#if !(SAML22) + /** 1.024KHz from 32KHz internal oscillator */ + RTC_CLOCK_SELECTION_OSC1K = OSC32KCTRL_RTCCTRL_RTCSEL_OSC1K_Val, + /** 32.768KHz from 32KHz internal oscillator */ + RTC_CLOCK_SELECTION_OSC32K = OSC32KCTRL_RTCCTRL_RTCSEL_OSC32K_Val, +#endif + /** 1.024KHz from 32KHz external oscillator */ + RTC_CLOCK_SELECTION_XOSC1K = OSC32KCTRL_RTCCTRL_RTCSEL_XOSC1K_Val, + /** 32.768KHz from 32.768KHz external crystal oscillator */ + RTC_CLOCK_SELECTION_XOSC32K = OSC32KCTRL_RTCCTRL_RTCSEL_XOSC32K_Val, +}; +#endif + +/** + * \brief Available operation modes for the RTC. + * + * RTC Count operating modes, to select the counting width and associated module + * operation. + */ +enum rtc_count_mode { + /** RTC Count module operates in 16-bit mode */ + RTC_COUNT_MODE_16BIT = 0, + /** RTC Count module operates in 32-bit mode */ + RTC_COUNT_MODE_32BIT = 1, +}; + +#if !defined (RTC_NUM_OF_COMP16) && defined(RTC_COMP16_NUM) +#define RTC_NUM_OF_COMP16 RTC_COMP16_NUM +#endif + +/** + * \brief Available compare channels. + * + * \note Not all compare channels are available in all devices and modes. + */ +enum rtc_count_compare { + /** Compare channel 0 */ + RTC_COUNT_COMPARE_0 = 0, +#if (RTC_NUM_OF_COMP16 > 1) || defined(__DOXYGEN__) + /** Compare channel 1 */ + RTC_COUNT_COMPARE_1 = 1, +#endif +#if (RTC_NUM_OF_COMP16 > 2) || defined(__DOXYGEN__) + /** Compare channel 2 */ + RTC_COUNT_COMPARE_2 = 2, +#endif +#if (RTC_NUM_OF_COMP16 > 3) || defined(__DOXYGEN__) + /** Compare channel 3 */ + RTC_COUNT_COMPARE_3 = 3, +#endif +#if (RTC_NUM_OF_COMP16 > 4) || defined(__DOXYGEN__) + /** Compare channel 4 */ + RTC_COUNT_COMPARE_4 = 4, +#endif +#if (RTC_NUM_OF_COMP16 > 5) || defined(__DOXYGEN__) + /** Compare channel 5 */ + RTC_COUNT_COMPARE_5 = 5, +#endif +}; + +#ifdef FEATURE_RTC_PERIODIC_INT +/** + * \brief Available periodic interval source. + */ +enum rtc_count_periodic_interval{ + /** Periodic interval 0 */ + RTC_COUNT_PERIODIC_INTERVAL_0 = 0, + /** Periodic interval 1 */ + RTC_COUNT_PERIODIC_INTERVAL_1 = 1, + /** Periodic interval 2 */ + RTC_COUNT_PERIODIC_INTERVAL_2 = 2, + /** Periodic interval 3 */ + RTC_COUNT_PERIODIC_INTERVAL_3 = 3, + /** Periodic interval 4 */ + RTC_COUNT_PERIODIC_INTERVAL_4 = 4, + /** Periodic interval 5 */ + RTC_COUNT_PERIODIC_INTERVAL_5 = 5, + /** Periodic interval 6 */ + RTC_COUNT_PERIODIC_INTERVAL_6 = 6, + /** Periodic interval 7 */ + RTC_COUNT_PERIODIC_INTERVAL_7 = 7, +}; +#endif + +#if RTC_COUNT_ASYNC == true +#ifdef FEATURE_RTC_PERIODIC_INT +/** + * \brief Callback types. + * + * The available callback types for the RTC count module. + */ +enum rtc_count_callback { + /** Callback for Periodic Interval 0 Interrupt */ + RTC_COUNT_CALLBACK_PERIODIC_INTERVAL_0 = 0, + /** Callback for Periodic Interval 1 Interrupt */ + RTC_COUNT_CALLBACK_PERIODIC_INTERVAL_1, + /** Callback for Periodic Interval 2 Interrupt */ + RTC_COUNT_CALLBACK_PERIODIC_INTERVAL_2, + /** Callback for Periodic Interval 3 Interrupt */ + RTC_COUNT_CALLBACK_PERIODIC_INTERVAL_3, + /** Callback for Periodic Interval 4 Interrupt */ + RTC_COUNT_CALLBACK_PERIODIC_INTERVAL_4, + /** Callback for Periodic Interval 5 Interrupt */ + RTC_COUNT_CALLBACK_PERIODIC_INTERVAL_5, + /** Callback for Periodic Interval 6 Interrupt */ + RTC_COUNT_CALLBACK_PERIODIC_INTERVAL_6, + /** Callback for Periodic Interval 7 Interrupt */ + RTC_COUNT_CALLBACK_PERIODIC_INTERVAL_7, + /** Callback for compare channel 0 */ + RTC_COUNT_CALLBACK_COMPARE_0, +# if (RTC_NUM_OF_COMP16 > 1) || defined(__DOXYGEN__) + /** Callback for compare channel 1 */ + RTC_COUNT_CALLBACK_COMPARE_1, +# endif +# if (RTC_NUM_OF_COMP16 > 2) || defined(__DOXYGEN__) + /** Callback for compare channel 2 */ + RTC_COUNT_CALLBACK_COMPARE_2, +# endif +# if (RTC_NUM_OF_COMP16 > 3) || defined(__DOXYGEN__) + /** Callback for compare channel 3 */ + RTC_COUNT_CALLBACK_COMPARE_3, +# endif +# if (RTC_NUM_OF_COMP16 > 4) || defined(__DOXYGEN__) + /** Callback for compare channel 4 */ + RTC_COUNT_CALLBACK_COMPARE_4, +# endif +# if (RTC_NUM_OF_COMP16 > 5) || defined(__DOXYGEN__) + /** Callback for compare channel 5 */ + RTC_COUNT_CALLBACK_COMPARE_5, +# endif + +#ifdef FEATURE_RTC_TAMPER_DETECTION + /** Callback for tamper */ + RTC_COUNT_CALLBACK_TAMPER, +#endif + + /** Callback for overflow */ + RTC_COUNT_CALLBACK_OVERFLOW, +# if !defined(__DOXYGEN__) + /** Total number of callbacks */ + _RTC_COUNT_CALLBACK_N +# endif +}; +#else +/** + * \brief Callback types. + * + * The available callback types for the RTC count module. + */ +enum rtc_count_callback { + /** Callback for compare channel 0 */ + RTC_COUNT_CALLBACK_COMPARE_0 = 0, +# if (RTC_NUM_OF_COMP16 > 1) || defined(__DOXYGEN__) + /** Callback for compare channel 1 */ + RTC_COUNT_CALLBACK_COMPARE_1, +# endif +# if (RTC_NUM_OF_COMP16 > 2) || defined(__DOXYGEN__) + /** Callback for compare channel 2 */ + RTC_COUNT_CALLBACK_COMPARE_2, +# endif +# if (RTC_NUM_OF_COMP16 > 3) || defined(__DOXYGEN__) + /** Callback for compare channel 3 */ + RTC_COUNT_CALLBACK_COMPARE_3, +# endif +# if (RTC_NUM_OF_COMP16 > 4) || defined(__DOXYGEN__) + /** Callback for compare channel 4 */ + RTC_COUNT_CALLBACK_COMPARE_4, +# endif +# if (RTC_NUM_OF_COMP16 > 5) || defined(__DOXYGEN__) + /** Callback for compare channel 5 */ + RTC_COUNT_CALLBACK_COMPARE_5, +# endif + +#ifdef FEATURE_RTC_TAMPER_DETECTION + /** Callback for tamper */ + RTC_COUNT_CALLBACK_TAMPER, +#endif + + /** Callback for overflow */ + RTC_COUNT_CALLBACK_OVERFLOW, +# if !defined(__DOXYGEN__) + /** Total number of callbacks */ + _RTC_COUNT_CALLBACK_N +# endif +}; +#endif + +# if !defined(__DOXYGEN__) +typedef void (*rtc_count_callback_t)(void); +# endif +#endif + +#ifdef FEATURE_RTC_PRESCALER_OFF +/** + * \brief RTC input clock prescaler settings. + * + * The available input clock prescaler values for the RTC count module. + */ +enum rtc_count_prescaler { + /** RTC prescaler is off, and the input clock frequency is + prescaled by a factor of 1 */ + RTC_COUNT_PRESCALER_OFF = RTC_MODE0_CTRLA_PRESCALER_OFF, + /** RTC input clock frequency is prescaled by a factor of 1 */ + RTC_COUNT_PRESCALER_DIV_1 = RTC_MODE0_CTRLA_PRESCALER_DIV1, + /** RTC input clock frequency is prescaled by a factor of 2 */ + RTC_COUNT_PRESCALER_DIV_2 = RTC_MODE0_CTRLA_PRESCALER_DIV2, + /** RTC input clock frequency is prescaled by a factor of 4 */ + RTC_COUNT_PRESCALER_DIV_4 = RTC_MODE0_CTRLA_PRESCALER_DIV4, + /** RTC input clock frequency is prescaled by a factor of 8 */ + RTC_COUNT_PRESCALER_DIV_8 = RTC_MODE0_CTRLA_PRESCALER_DIV8, + /** RTC input clock frequency is prescaled by a factor of 16 */ + RTC_COUNT_PRESCALER_DIV_16 = RTC_MODE0_CTRLA_PRESCALER_DIV16, + /** RTC input clock frequency is prescaled by a factor of 32 */ + RTC_COUNT_PRESCALER_DIV_32 = RTC_MODE0_CTRLA_PRESCALER_DIV32, + /** RTC input clock frequency is prescaled by a factor of 64 */ + RTC_COUNT_PRESCALER_DIV_64 = RTC_MODE0_CTRLA_PRESCALER_DIV64, + /** RTC input clock frequency is prescaled by a factor of 128 */ + RTC_COUNT_PRESCALER_DIV_128 = RTC_MODE0_CTRLA_PRESCALER_DIV128, + /** RTC input clock frequency is prescaled by a factor of 256 */ + RTC_COUNT_PRESCALER_DIV_256 = RTC_MODE0_CTRLA_PRESCALER_DIV256, + /** RTC input clock frequency is prescaled by a factor of 512 */ + RTC_COUNT_PRESCALER_DIV_512 = RTC_MODE0_CTRLA_PRESCALER_DIV512, + /** RTC input clock frequency is prescaled by a factor of 1024 */ + RTC_COUNT_PRESCALER_DIV_1024 = RTC_MODE0_CTRLA_PRESCALER_DIV1024, +}; +#else +/** + * \brief RTC input clock prescaler settings. + * + * The available input clock prescaler values for the RTC count module. + */ +enum rtc_count_prescaler { + /** RTC input clock frequency is prescaled by a factor of 1 */ + RTC_COUNT_PRESCALER_DIV_1 = RTC_MODE0_CTRL_PRESCALER_DIV1, + /** RTC input clock frequency is prescaled by a factor of 2 */ + RTC_COUNT_PRESCALER_DIV_2 = RTC_MODE0_CTRL_PRESCALER_DIV2, + /** RTC input clock frequency is prescaled by a factor of 4 */ + RTC_COUNT_PRESCALER_DIV_4 = RTC_MODE0_CTRL_PRESCALER_DIV4, + /** RTC input clock frequency is prescaled by a factor of 8 */ + RTC_COUNT_PRESCALER_DIV_8 = RTC_MODE0_CTRL_PRESCALER_DIV8, + /** RTC input clock frequency is prescaled by a factor of 16 */ + RTC_COUNT_PRESCALER_DIV_16 = RTC_MODE0_CTRL_PRESCALER_DIV16, + /** RTC input clock frequency is prescaled by a factor of 32 */ + RTC_COUNT_PRESCALER_DIV_32 = RTC_MODE0_CTRL_PRESCALER_DIV32, + /** RTC input clock frequency is prescaled by a factor of 64 */ + RTC_COUNT_PRESCALER_DIV_64 = RTC_MODE0_CTRL_PRESCALER_DIV64, + /** RTC input clock frequency is prescaled by a factor of 128 */ + RTC_COUNT_PRESCALER_DIV_128 = RTC_MODE0_CTRL_PRESCALER_DIV128, + /** RTC input clock frequency is prescaled by a factor of 256 */ + RTC_COUNT_PRESCALER_DIV_256 = RTC_MODE0_CTRL_PRESCALER_DIV256, + /** RTC input clock frequency is prescaled by a factor of 512 */ + RTC_COUNT_PRESCALER_DIV_512 = RTC_MODE0_CTRL_PRESCALER_DIV512, + /** RTC input clock frequency is prescaled by a factor of 1024 */ + RTC_COUNT_PRESCALER_DIV_1024 = RTC_MODE0_CTRL_PRESCALER_DIV1024, +}; +#endif + +/** + * \brief RTC Count event enable/disable structure. + * + * Event flags for the \ref rtc_count_enable_events() and + * \ref rtc_count_disable_events(). + */ +struct rtc_count_events { + /** Generate an output event on each overflow of the RTC count */ + bool generate_event_on_overflow; + /** Generate an output event on a compare channel match against the RTC + * count */ + bool generate_event_on_compare[RTC_NUM_OF_COMP16]; + /** Generate an output event periodically at a binary division of the RTC + * counter frequency */ + bool generate_event_on_periodic[8]; +#ifdef FEATURE_RTC_TAMPER_DETECTION + /** Generate an output event on every tamper input */ + bool generate_event_on_tamper; + /** Tamper input event and capture the COUNT value */ + bool on_event_to_tamper; +#endif +}; + +#if !defined(__DOXYGEN__) +/** + * \brief Device structure. + */ +struct rtc_module { + /** RTC hardware module */ + Rtc *hw; + /** Operation mode of count */ + enum rtc_count_mode mode; +#ifdef FEATURE_RTC_CONTINUOUSLY_UPDATED + /** Set if counter value should be continuously updated */ + bool continuously_update; +#endif +# if RTC_COUNT_ASYNC == true + /** Pointers to callback functions */ + volatile rtc_count_callback_t callbacks[_RTC_COUNT_CALLBACK_N]; + /** Mask for registered callbacks */ + volatile uint16_t registered_callback; + /** Mask for enabled callbacks */ + volatile uint16_t enabled_callback; +# endif +}; +#endif + +/** + * \brief RTC Count configuration structure. + * + * Configuration structure for the RTC instance. This structure should + * be initialized using the \ref rtc_count_get_config_defaults() before any + * user configurations are set. + */ +struct rtc_count_config { + /** Input clock prescaler for the RTC module */ + enum rtc_count_prescaler prescaler; + /** Select the operation mode of the RTC */ + enum rtc_count_mode mode; + /** If true, clears the counter value on compare match. Only available + * whilst running in 32-bit mode */ + bool clear_on_match; +#ifdef FEATURE_RTC_CONTINUOUSLY_UPDATED + /** Continuously update the counter value so no synchronization is + * needed for reading */ + bool continuously_update; +#endif +#if (SAML21XXXB) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + /** Enable count read synchronization. The COUNT value requires + * synchronization when reading. Disabling the synchronization + * will prevent the COUNT value from displaying the current value. */ + bool enable_read_sync; +#endif + + /** Array of Compare values. Not all Compare values are available in 32-bit + * mode */ + uint32_t compare_values[RTC_NUM_OF_COMP16]; +}; + + +/** + * \name Configuration and Initialization + * @{ + */ + +/** + * \brief Gets the RTC default configurations. + * + * Initializes the configuration structure to default values. This + * function should be called at the start of any RTC initialization. + * + * The default configuration is: + * - Input clock divided by a factor of 1024 + * - RTC in 32-bit mode + * - Clear on compare match off + * - Continuously sync count register off + * - No event source on + * - All compare values equal 0 + * - Count read synchronization is enabled for SAM L22 + * + * \param[out] config Configuration structure to be initialized to default + * values + */ +static inline void rtc_count_get_config_defaults( + struct rtc_count_config *const config) +{ + /* Sanity check argument */ + Assert(config); + + /* Set default into configuration structure */ + config->prescaler = RTC_COUNT_PRESCALER_DIV_1024; + config->mode = RTC_COUNT_MODE_32BIT; + config->clear_on_match = false; + +#ifdef FEATURE_RTC_CONTINUOUSLY_UPDATED + config->continuously_update = false; +#endif +#if (SAML21XXXB) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + config->enable_read_sync = true; +#endif + + for (uint8_t i = 0; i < RTC_NUM_OF_COMP16; i++) { + config->compare_values[i] = 0; + } +} + +void rtc_count_reset(struct rtc_module *const module); +void rtc_count_enable(struct rtc_module *const module); +void rtc_count_disable(struct rtc_module *const module); + +#if (RTC_INST_NUM > 1) && !defined(__DOXYGEN__) +/** + * \internal Find the index of given RTC module instance. + * + * \param[in] RTC module instance pointer + * + * \return Index of the given AC module instance. + */ +uint8_t _rtc_get_inst_index( + Rtc *const hw) +{ + /* List of available RTC modules */ + static Rtc *const rtc_modules[RTC_INST_NUM] = RTC_INSTS; + + /* Find index for RTC instance */ + for (uint32_t i = 0; i < RTC_INST_NUM; i++) { + if (hw == rtc_modules[i]) { + return i; + } + } + + /* Invalid data given */ + Assert(false); + return 0; +} +#endif /* (RTC_INST_NUM > 1) && !defined(__DOXYGEN__) */ + +enum status_code rtc_count_init( + struct rtc_module *const module, + Rtc *const hw, + const struct rtc_count_config *const config); + +enum status_code rtc_count_frequency_correction( + struct rtc_module *const module, + const int8_t value); + +/** @} */ + +/** \name Count and Compare Value Management + * @{ + */ +enum status_code rtc_count_set_count( + struct rtc_module *const module, + const uint32_t count_value); + +uint32_t rtc_count_get_count(struct rtc_module *const module); + +enum status_code rtc_count_set_compare( + struct rtc_module *const module, + const uint32_t comp_value, + const enum rtc_count_compare comp_index); + +enum status_code rtc_count_get_compare( + struct rtc_module *const module, + uint32_t *const comp_value, + const enum rtc_count_compare comp_index); + +enum status_code rtc_count_set_period( + struct rtc_module *const module, + uint16_t period_value); + +enum status_code rtc_count_get_period( + struct rtc_module *const module, + uint16_t *const period_value); + +/** @} */ + + +/** \name Status Management + * @{ + */ + +/** + * \brief Check if an RTC overflow has occurred. + * + * Checks the overflow flag in the RTC. The flag is set when there + * is an overflow in the clock. + * + * \param[in,out] module RTC hardware module + * + * \return Overflow state of the RTC module. + * + * \retval true If the RTC count value has overflowed + * \retval false If the RTC count value has not overflowed + */ + +static inline bool rtc_count_is_overflow(struct rtc_module *const module) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + Rtc *const rtc_module = module->hw; + + /* Return status of flag */ + return (rtc_module->MODE0.INTFLAG.reg & RTC_MODE0_INTFLAG_OVF); +} + +/** + * \brief Clears the RTC overflow flag. + * + * Clears the RTC module counter overflow flag, so that new overflow conditions + * can be detected. + * + * \param[in,out] module RTC hardware module + */ +static inline void rtc_count_clear_overflow(struct rtc_module *const module) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + Rtc *const rtc_module = module->hw; + + /* Clear OVF flag */ + rtc_module->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_OVF; +} + +#ifdef FEATURE_RTC_PERIODIC_INT +/** + * \brief Check if an RTC periodic interval interrupt has occurred. + * + * Checks the periodic interval flag in the RTC. + * + * \param[in,out] module RTC hardware module + * \param[in] n RTC periodic interval interrupt + * + * \return Periodic interval interrupt state of the RTC module. + * + * \retval true RTC periodic interval interrupt occurs + * \retval false RTC periodic interval interrupt doesn't occur + */ +static inline bool rtc_count_is_periodic_interval(struct rtc_module *const module, + enum rtc_count_periodic_interval n) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + Rtc *const rtc_module = module->hw; + + /* Return status of flag */ + return (rtc_module->MODE0.INTFLAG.reg & RTC_MODE0_INTFLAG_PER(1 << n)); +} + +/** + * \brief Clears the RTC periodic interval flag. + * + * Clears the RTC module counter periodic interval flag, so that new periodic + * interval conditions can be detected. + * + * \param[in,out] module RTC hardware module + * \param[in] n RTC periodic interval interrupt + */ +static inline void rtc_count_clear_periodic_interval(struct rtc_module *const module, + enum rtc_count_periodic_interval n) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + Rtc *const rtc_module = module->hw; + + /* Clear periodic interval flag */ + rtc_module->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_PER(1 << n); +} +#endif +bool rtc_count_is_compare_match( + struct rtc_module *const module, + const enum rtc_count_compare comp_index); + +enum status_code rtc_count_clear_compare_match( + struct rtc_module *const module, + const enum rtc_count_compare comp_index); + +/** @} */ + + +/** + * \name Event Management + * @{ + */ + +/** + * \brief Enables an RTC event output. + * + * Enables one or more output events from the RTC module. See + * \ref rtc_count_events for a list of events this module supports. + * + * \note Events cannot be altered while the module is enabled. + * + * \param[in,out] module RTC hardware module + * \param[in] events Struct containing flags of events to enable + */ +static inline void rtc_count_enable_events( + struct rtc_module *const module, + struct rtc_count_events *const events) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + Rtc *const rtc_module = module->hw; + + uint32_t event_mask = 0; + + /* Check if the user has requested an overflow event */ + if (events->generate_event_on_overflow) { + event_mask |= RTC_MODE0_EVCTRL_OVFEO; + } + + /* Check if the user has requested any compare events */ + for (uint8_t i = 0; i < RTC_NUM_OF_COMP16; i++) { + if (events->generate_event_on_compare[i]) { + event_mask |= RTC_MODE0_EVCTRL_CMPEO(1 << i); + } + } + + /* Check if the user has requested any periodic events */ + for (uint8_t i = 0; i < 8; i++) { + if (events->generate_event_on_periodic[i]) { + event_mask |= RTC_MODE0_EVCTRL_PEREO(1 << i); + } + } + +#ifdef FEATURE_RTC_TAMPER_DETECTION + /* Check if the user has requested a tamper event output. */ + if (events->generate_event_on_tamper) { + event_mask |= RTC_MODE0_EVCTRL_TAMPEREO; + } + + /* Check if the user has requested a tamper event input. */ + if (events->on_event_to_tamper) { + event_mask |= RTC_MODE0_EVCTRL_TAMPEVEI; + } +#endif + + /* Enable given event(s). */ + rtc_module->MODE0.EVCTRL.reg |= event_mask; +} + +/** + * \brief Disables an RTC event output. + * + * Disabled one or more output events from the RTC module. See + * \ref rtc_count_events for a list of events this module supports. + * + * \note Events cannot be altered while the module is enabled. + * + * \param[in,out] module RTC hardware module + * \param[in] events Struct containing flags of events to disable + */ +static inline void rtc_count_disable_events( + struct rtc_module *const module, + struct rtc_count_events *const events) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + Rtc *const rtc_module = module->hw; + + uint32_t event_mask = 0; + + /* Check if the user has requested an overflow event */ + if (events->generate_event_on_overflow) { + event_mask |= RTC_MODE0_EVCTRL_OVFEO; + } + + /* Check if the user has requested any compare events */ + for (uint8_t i = 0; i < RTC_NUM_OF_COMP16; i++) { + if (events->generate_event_on_compare[i]) { + event_mask |= RTC_MODE0_EVCTRL_CMPEO(1 << i); + } + } + + /* Check if the user has requested any periodic events */ + for (uint8_t i = 0; i < 8; i++) { + if (events->generate_event_on_periodic[i]) { + event_mask |= RTC_MODE0_EVCTRL_PEREO(1 << i); + } + } + +#ifdef FEATURE_RTC_TAMPER_DETECTION + /* Check if the user has requested a tamper event output. */ + if (events->generate_event_on_tamper) { + event_mask |= RTC_MODE0_EVCTRL_TAMPEREO; + } + + /* Check if the user has requested a tamper event input. */ + if (events->on_event_to_tamper) { + event_mask |= RTC_MODE0_EVCTRL_TAMPEVEI; + } +#endif + + /* Disable given event(s). */ + rtc_module->MODE0.EVCTRL.reg &= ~event_mask; +} + +/** @} */ + +#ifdef FEATURE_RTC_GENERAL_PURPOSE_REG +/** + * \name RTC General Purpose Registers + * @{ + */ + +/** + * \brief Write a value into general purpose register. + * + * \param[in] module Pointer to the software instance struct + * \param[in] n General purpose type + * \param[in] index General purpose register index (0..3) + * + */ +static inline void rtc_write_general_purpose_reg( + struct rtc_module *const module, + const uint8_t index, + uint32_t value) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + Assert(index <= 3); + + Rtc *const rtc_module = module->hw; + + rtc_module->MODE0.GP[index].reg = value; +} + +/** + * \brief Read the value from general purpose register. + * + * \param[in] module Pointer to the software instance struct + * \param[in] index General purpose register index (0..3) + * + * \return Value of general purpose register. + */ +static inline uint32_t rtc_read_general_purpose_reg( + struct rtc_module *const module, + const uint8_t index) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + Assert(index <= 3); + + Rtc *const rtc_module = module->hw; + + return rtc_module->MODE0.GP[index].reg; +} + +/** @} */ +#endif + +#ifdef FEATURE_RTC_TAMPER_DETECTION +#include "rtc_tamper.h" +/** + * \brief Get the tamper stamp value. + * + * \param[in,out] module Pointer to the software instance struct + * + * \return The current tamper stamp value as a 32-bit unsigned integer. + */ +uint32_t rtc_tamper_get_stamp (struct rtc_module *const module); +#endif + + +/** @} */ + +#ifdef __cplusplus +} +#endif + +/** + * \page asfdoc_sam0_rtc_count_extra Extra Information for RTC COUNT Driver + * + * \section asfdoc_sam0_rtc_count_extra_acronyms Acronyms + * Below is a table listing the acronyms used in this module, along with their + * intended meanings. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Acronym + * Description + *
RTCReal Time Counter
PPMPart Per Million
RCResistor/Capacitor
+ * + * + * \section asfdoc_sam0_rtc_count_extra_dependencies Dependencies + * This driver has the following dependencies: + * + * - None + * + * + * \section asfdoc_sam0_rtc_count_extra_errata Errata + * There are no errata related to this driver. + * + * + * \section asfdoc_sam0_rtc_count_extra_history Module History + * An overview of the module history is presented in the table below, with + * details on the enhancements and fixes made to the module since its first + * release. The current version of this corresponds to the newest version in + * the table. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Changelog
Added support for SAM C21
Added support for SAM L21/L22
Added support for SAM R30
Added support for RTC tamper feature
+ * Added driver instance parameter to all API function calls, except + * get_config_defaults + *
+ * Updated initialization function to also enable the digital interface + * clock to the module if it is disabled + *
Initial Release
+ */ + +/** + * \page asfdoc_sam0_rtc_count_exqsg Examples for RTC (COUNT) Driver + * + * This is a list of the available Quick Start guides (QSGs) and example + * applications for \ref asfdoc_sam0_rtc_count_group. QSGs are simple + * examples with step-by-step instructions to configure and use this driver in a + * selection of use cases. Note that a QSG can be compiled as a standalone + * application or be added to the user application. + * + * - \subpage asfdoc_sam0_rtc_count_basic_use_case + * \if RTC_COUNT_CALLBACK_MODE + * - \subpage asfdoc_sam0_rtc_count_callback_use_case + * \endif + * - \subpage asfdoc_sam0_rtc_tamper_dma_use_case + * + * \page asfdoc_sam0_rtc_count_document_revision_history Document Revision History + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Doc. Rev.DateComments
42111E12/2015Added support for SAM L21/L22, SAM C21, SAM D09, SAMR30/R34 and SAM DA1
42111D12/2014Added support for SAM R21 and SAM D10/D11
42111C01/2014Added support for SAM D21
42111B06/2013Added additional documentation on the event system. Corrected + * documentation typos.
42111A06/2013Initial release
+ */ + +#endif /* RTC_COUNT_H_INCLUDED */ diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/rtc/rtc_count_interrupt.h b/src/boards/mcu/samr34/ASF/sam0/drivers/rtc/rtc_count_interrupt.h new file mode 100644 index 000000000..1f1631a0c --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/rtc/rtc_count_interrupt.h @@ -0,0 +1,80 @@ +/** + * \file + * + * \brief SAM RTC Driver (Count Interrupt Mode) + * + * Copyright (c) 2013-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#ifndef RTC_COUNT_INTERRUPT_H_INCLUDED +#define RTC_COUNT_INTERRUPT_H_INCLUDED + +#include "rtc_count.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup asfdoc_sam0_rtc_count_group + * @{ + */ + + /** + * \name Callbacks + * @{ + */ +enum status_code rtc_count_register_callback( + struct rtc_module *const module, + rtc_count_callback_t callback, + enum rtc_count_callback callback_type); + +enum status_code rtc_count_unregister_callback( + struct rtc_module *const module, + enum rtc_count_callback callback_type); + +void rtc_count_enable_callback( + struct rtc_module *const module, + enum rtc_count_callback callback_type); + +void rtc_count_disable_callback( + struct rtc_module *const module, + enum rtc_count_callback callback_type); + +/** @} */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* RTC_COUNT_INTERRUPT_H_INCLUDED */ diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/rtc/rtc_sam_l_c/rtc_count.c b/src/boards/mcu/samr34/ASF/sam0/drivers/rtc/rtc_sam_l_c/rtc_count.c new file mode 100644 index 000000000..dddf0b9b1 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/rtc/rtc_sam_l_c/rtc_count.c @@ -0,0 +1,941 @@ +/** + * \file + * + * \brief SAM RTC Driver (Count Mode) + * + * Copyright (c) 2012-2020 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#include "rtc_count.h" +#include +#include +#include "conf_rtc.h" + +#if !defined(__DOXYGEN__) +struct rtc_module *_rtc_instance[RTC_INST_NUM]; +#endif + +#if !defined(RTC_CLOCK_SOURCE) +# warning RTC_CLOCK_SOURCE is not defined, assuming RTC_CLOCK_SELECTION_ULP1K. +# define RTC_CLOCK_SOURCE RTC_CLOCK_SELECTION_ULP1K +#endif + +/** + * \brief Determines if the hardware module(s) are currently synchronizing to the bus. + * + * Checks to see if the underlying hardware peripheral module(s) are currently + * synchronizing across multiple clock domains to the hardware bus, This + * function can be used to delay further operations on a module until such time + * that it is ready, to prevent blocking delays for synchronization in the + * user application. + * + * \param[in] module RTC hardware module + * + * \return Synchronization status of the underlying hardware module(s). + * + * \retval true if the module synchronization is ongoing + * \retval false if the module has completed synchronization + */ +static bool rtc_count_is_syncing(struct rtc_module *const module) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + Rtc *const rtc_module = module->hw; + + if (rtc_module->MODE0.SYNCBUSY.reg) { + return true; + } + + return false; +} + +/** + * \brief Enables the RTC module. + * + * Enables the RTC module once it has been configured, ready for use. Most + * module configuration parameters cannot be altered while the module is enabled. + * + * \param[in,out] module RTC hardware module + */ +void rtc_count_enable(struct rtc_module *const module) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + Rtc *const rtc_module = module->hw; + +#if RTC_COUNT_ASYNC == true + system_interrupt_enable(SYSTEM_INTERRUPT_MODULE_RTC); +#endif + + while (rtc_count_is_syncing(module)) { + /* Wait for synchronization */ + } + + /* Enable RTC module. */ + rtc_module->MODE0.CTRLA.reg |= RTC_MODE0_CTRLA_ENABLE; + + while (rtc_count_is_syncing(module)) { + /* Wait for synchronization */ + } +} + +/** + * \brief Disables the RTC module. + * + * Disables the RTC module. + * + * \param[in,out] module RTC hardware module + */ +void rtc_count_disable(struct rtc_module *const module) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + Rtc *const rtc_module = module->hw; + +#if RTC_COUNT_ASYNC == true + system_interrupt_disable(SYSTEM_INTERRUPT_MODULE_RTC); +#endif + + while (rtc_count_is_syncing(module)) { + /* Wait for synchronization */ + } + + /* Disbale interrupt */ + rtc_module->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_MASK; + /* Clear interrupt flag */ + rtc_module->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_MASK; + + /* Disable RTC module. */ + rtc_module->MODE0.CTRLA.reg &= ~RTC_MODE0_CTRLA_ENABLE; + + while (rtc_count_is_syncing(module)) { + /* Wait for synchronization */ + } +} + +/** + * \brief Resets the RTC module. + * Resets the RTC to hardware defaults. + * + * \param[in,out] module Pointer to the software instance struct + */ +void rtc_count_reset(struct rtc_module *const module) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + Rtc *const rtc_module = module->hw; + + /* Disable module before reset. */ + rtc_count_disable(module); + +#if RTC_COUNT_ASYNC == true + module->registered_callback = 0; + module->enabled_callback = 0; +#endif + + while (rtc_count_is_syncing(module)) { + /* Wait for synchronization */ + } + + /* Initiate software reset. */ + rtc_module->MODE0.CTRLA.reg |= RTC_MODE0_CTRLA_SWRST; + + while (rtc_count_is_syncing(module)) { + /* Wait for synchronization */ + } +} + +/** + * \internal Applies the given configuration. + * + * Sets the configurations given from the configuration structure to the + * hardware module + * + * \param[in,out] module Pointer to the software instance struct + * \param[in] config Pointer to the configuration structure + * + * \return Status of the configuration procedure. + * \retval STATUS_OK RTC configurations was set successfully + * \retval STATUS_ERR_INVALID_ARG If invalid argument(s) were given + */ +static enum status_code _rtc_count_set_config( + struct rtc_module *const module, + const struct rtc_count_config *const config) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + Rtc *const rtc_module = module->hw; + +#if SAML21 || SAMR30 || (SAMR34) || (SAMR35) || (WLR089) + rtc_module->MODE0.CTRLA.reg = RTC_MODE0_CTRLA_MODE(0) +#if (SAML21XXXB) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + | (config->enable_read_sync << RTC_MODE0_CTRLA_COUNTSYNC_Pos) +#endif + | config->prescaler; +#endif +#if (SAMC20) || (SAMC21) || (SAML22) + rtc_module->MODE0.CTRLA.reg = RTC_MODE0_CTRLA_MODE(0) | config->prescaler + | (config->enable_read_sync << RTC_MODE0_CTRLA_COUNTSYNC_Pos); +#endif + + /* Set mode and clear on match if applicable. */ + switch (config->mode) { + case RTC_COUNT_MODE_32BIT: + /* Set 32-bit mode and clear on match if applicable. */ + rtc_module->MODE0.CTRLA.reg |= RTC_MODE0_CTRLA_MODE(0); + + /* Check if clear on compare match should be set. */ + if (config->clear_on_match) { + /* Set clear on match. */ + rtc_module->MODE0.CTRLA.reg |= RTC_MODE0_CTRLA_MATCHCLR; + } + /* Set compare values. */ + for (uint8_t i = 0; i < RTC_COMP32_NUM; i++) { + rtc_count_set_compare(module, config->compare_values[i], + (enum rtc_count_compare)i); + } + break; + + case RTC_COUNT_MODE_16BIT: + /* Set 16bit mode. */ + rtc_module->MODE1.CTRLA.reg |= RTC_MODE1_CTRLA_MODE(1); + + /* Check if match on clear is set, and return invalid + * argument if set. */ + if (config->clear_on_match) { + Assert(false); + return STATUS_ERR_INVALID_ARG; + } + /* Set compare values. */ + for (uint8_t i = 0; i < RTC_NUM_OF_COMP16; i++) { + rtc_count_set_compare(module, config->compare_values[i], + (enum rtc_count_compare)i); + } + break; + default: + Assert(false); + return STATUS_ERR_INVALID_ARG; + } + + /* Return status OK if everything was configured. */ + return STATUS_OK; +} + +/** + * \brief Initializes the RTC module with given configurations. + * + * Initializes the module, setting up all given configurations to provide + * the desired functionality of the RTC. + * + * \param[out] module Pointer to the software instance struct + * \param[in] hw Pointer to hardware instance + * \param[in] config Pointer to the configuration structure + * + * \return Status of the initialization procedure. + * \retval STATUS_OK If the initialization was run stressfully + * \retval STATUS_ERR_INVALID_ARG If invalid argument(s) were given + */ +enum status_code rtc_count_init( + struct rtc_module *const module, + Rtc *const hw, + const struct rtc_count_config *const config) +{ + /* Sanity check arguments */ + Assert(module); + Assert(hw); + Assert(config); + + /* Initialize device instance */ + module->hw = hw; + + /* Turn on the digital interface clock */ + system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBA, MCLK_APBAMASK_RTC); + + /* Select RTC clock */ + OSC32KCTRL->RTCCTRL.reg = RTC_CLOCK_SOURCE; + + /* Reset module to hardware defaults. */ + rtc_count_reset(module); + + /* Save conf_struct internally for continued use. */ + module->mode = config->mode; + +# if (RTC_INST_NUM == 1) + _rtc_instance[0] = module; +# else + /* Register this instance for callbacks*/ + _rtc_instance[_rtc_get_inst_index(hw)] = module; +# endif + + /* Set config and return status. */ + return _rtc_count_set_config(module, config); +} + +/** + * \brief Set the current count value to desired value. + * + * Sets the value of the counter to the specified value. + * + * \param[in,out] module Pointer to the software instance struct + * \param[in] count_value The value to be set in count register + * + * \return Status of setting the register. + * \retval STATUS_OK If everything was executed correctly + * \retval STATUS_ERR_INVALID_ARG If invalid argument(s) were provided + */ +enum status_code rtc_count_set_count( + struct rtc_module *const module, + const uint32_t count_value) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + Rtc *const rtc_module = module->hw; + + while (rtc_count_is_syncing(module)) { + /* Wait for synchronization */ + } + + /* Set count according to mode */ + switch(module->mode){ + case RTC_COUNT_MODE_32BIT: + /* Write value to register. */ + rtc_module->MODE0.COUNT.reg = count_value; + break; + case RTC_COUNT_MODE_16BIT: + /* Check if 16-bit value is provided. */ + if(count_value > 0xffff){ + return STATUS_ERR_INVALID_ARG; + } + + /* Write value to register. */ + rtc_module->MODE1.COUNT.reg = (uint32_t)count_value; + + break; + + default: + Assert(false); + return STATUS_ERR_INVALID_ARG; + } + + while (rtc_count_is_syncing(module)) { + /* Wait for synchronization */ + } + return STATUS_OK; +} + +/** + * \brief Get the current count value. + * + * \param[in,out] module Pointer to the software instance struct + * + * Returns the current count value. + * + * \return The current counter value as a 32-bit unsigned integer. + */ +uint32_t rtc_count_get_count(struct rtc_module *const module) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + Rtc *const rtc_module = module->hw; + + /* Initialize return value. */ + uint32_t ret_val; + + while (rtc_count_is_syncing(module)) { + /* Wait for synchronization */ + } + + /* Read value based on mode. */ + switch (module->mode) { + case RTC_COUNT_MODE_32BIT: + /* Return count value in 32-bit mode. */ + ret_val = rtc_module->MODE0.COUNT.reg; + + break; + + case RTC_COUNT_MODE_16BIT: + /* Return count value in 16-bit mode. */ + ret_val = (uint32_t)rtc_module->MODE1.COUNT.reg; + + break; + + default: + Assert(false); + /* Counter not initialized. Assume counter value 0.*/ + ret_val = 0; + break; + } + + return ret_val; +} + +/** + * \brief Set the compare value for the specified compare. + * + * Sets the value specified by the implementer to the requested compare. + * + * \note Compare 4 and 5 are only available in 16-bit mode. + * + * \param[in,out] module Pointer to the software instance struct + * \param[in] comp_value The value to be written to the compare + * \param[in] comp_index Index of the compare to set + * + * \return Status indicating if compare was successfully set. + * \retval STATUS_OK If compare was successfully set + * \retval STATUS_ERR_INVALID_ARG If invalid argument(s) were provided + * \retval STATUS_ERR_BAD_FORMAT If the module was not initialized in a mode + */ +enum status_code rtc_count_set_compare( + struct rtc_module *const module, + const uint32_t comp_value, + const enum rtc_count_compare comp_index) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + Rtc *const rtc_module = module->hw; + + while (rtc_count_is_syncing(module)) { + /* Wait for synchronization */ + } + + /* Set compare values based on operation mode. */ + switch (module->mode) { + case RTC_COUNT_MODE_32BIT: + /* Check sanity of comp_index. */ + if ((uint32_t)comp_index > RTC_COMP32_NUM) { + return STATUS_ERR_INVALID_ARG; + } + + /* Set compare value for COMP. */ + rtc_module->MODE0.COMP[comp_index].reg = comp_value; + + break; + + case RTC_COUNT_MODE_16BIT: + /* Check sanity of comp_index. */ + if ((uint32_t)comp_index > RTC_NUM_OF_COMP16) { + return STATUS_ERR_INVALID_ARG; + } + + /* Check that 16-bit value is provided. */ + if (comp_value > 0xffff) { + Assert(false); + return STATUS_ERR_INVALID_ARG; + } + + /* Set compare value for COMP. */ + rtc_module->MODE1.COMP[comp_index].reg = comp_value & 0xffff; + + break; + + default: + Assert(false); + return STATUS_ERR_BAD_FORMAT; + } + + while (rtc_count_is_syncing(module)) { + /* Wait for synchronization */ + } + + /* Return status if everything is OK. */ + return STATUS_OK; +} + +/** + * \brief Get the current compare value of specified compare. + * + * Retrieves the current value of the specified compare. + * + * \note Compare 4 and 5 are only available in 16-bit mode. + * + * \param[in,out] module Pointer to the software instance struct + * \param[out] comp_value Pointer to 32-bit integer that will be populated with + * the current compare value + * \param[in] comp_index Index of compare to check + * + * \return Status of the reading procedure. + * \retval STATUS_OK If the value was read correctly + * \retval STATUS_ERR_INVALID_ARG If invalid argument(s) were provided + * \retval STATUS_ERR_BAD_FORMAT If the module was not initialized in a mode + */ +enum status_code rtc_count_get_compare( + struct rtc_module *const module, + uint32_t *const comp_value, + const enum rtc_count_compare comp_index) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + Rtc *const rtc_module = module->hw; + + while (rtc_count_is_syncing(module)) { + /* Wait for synchronization */ + } + + switch (module->mode) { + case RTC_COUNT_MODE_32BIT: + /* Check sanity of comp_index. */ + if ((uint32_t)comp_index > RTC_COMP32_NUM) { + return STATUS_ERR_INVALID_ARG; + } + + /* Get compare value for COMP. */ + *comp_value = rtc_module->MODE0.COMP[comp_index].reg; + + break; + + case RTC_COUNT_MODE_16BIT: + /* Check sanity of comp_index. */ + if ((uint32_t)comp_index > RTC_NUM_OF_COMP16) { + return STATUS_ERR_INVALID_ARG; + } + + /* Get compare value for COMP. */ + *comp_value = (uint32_t)rtc_module->MODE1.COMP[comp_index].reg; + + break; + + default: + Assert(false); + return STATUS_ERR_BAD_FORMAT; + } + /* Return status showing everything is OK. */ + return STATUS_OK; +} + +/** + * \brief Retrieves the value of period. + * + * Retrieves the value of the period for the 16-bit mode counter. + * + * \note Only available in 16-bit mode. + * + * \param[in,out] module Pointer to the software instance struct + * \param[out] period_value Pointer to value for return argument + * + * \return Status of getting the period value. + * \retval STATUS_OK If the period value was read correctly + * \retval STATUS_ERR_UNSUPPORTED_DEV If incorrect mode was set + */ +enum status_code rtc_count_get_period( + struct rtc_module *const module, + uint16_t *const period_value) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + Rtc *const rtc_module = module->hw; + + while (rtc_count_is_syncing(module)) { + /* Wait for synchronization */ + } + + /* Check that correct mode is set. */ + if (module->mode != RTC_COUNT_MODE_16BIT) { + return STATUS_ERR_UNSUPPORTED_DEV; + } + + /* Returns the value. */ + *period_value = rtc_module->MODE1.PER.reg; + + return STATUS_OK; +} + +/** + * \brief Set the given value to the period. + * + * Sets the given value to the period. + * + * \note Only available in 16-bit mode. + * + * \param[in,out] module Pointer to the software instance struct + * \param[in] period_value The value to set to the period + * + * \return Status of setting the period value. + * \retval STATUS_OK If the period was set correctly + * \retval STATUS_ERR_UNSUPPORTED_DEV If module is not operated in 16-bit mode + */ +enum status_code rtc_count_set_period( + struct rtc_module *const module, + const uint16_t period_value) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + Rtc *const rtc_module = module->hw; + + /* Check that correct mode is set. */ + if (module->mode != RTC_COUNT_MODE_16BIT) { + return STATUS_ERR_UNSUPPORTED_DEV; + } + + while (rtc_count_is_syncing(module)) { + /* Wait for synchronization */ + } + + /* Write value to register. */ + rtc_module->MODE1.PER.reg = period_value; + + while (rtc_count_is_syncing(module)) { + /* Wait for synchronization */ + } + + return STATUS_OK; +} + +/** + * \brief Check if RTC compare match has occurred. + * + * Checks the compare flag to see if a match has occurred. The compare flag is + * set when there is a compare match between counter and the compare. + * + * \note Compare 4 and 5 are only available in 16-bit mode. + * + * \param[in,out] module Pointer to the software instance struct + * \param[in] comp_index Index of compare to check current flag + */ +bool rtc_count_is_compare_match( + struct rtc_module *const module, + const enum rtc_count_compare comp_index) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + Rtc *const rtc_module = module->hw; + + /* Check sanity. */ + switch (module->mode) { + case RTC_COUNT_MODE_32BIT: + /* Check sanity for 32-bit mode. */ + if (comp_index > RTC_COMP32_NUM) { + return false; + } + + break; + + case RTC_COUNT_MODE_16BIT: + /* Check sanity for 16-bit mode. */ + if (comp_index > RTC_NUM_OF_COMP16) { + return false; + } + + break; + + default: + Assert(false); + return false; + } + + /* Set status of INTFLAG as return argument. */ + return (rtc_module->MODE0.INTFLAG.reg & RTC_MODE1_INTFLAG_CMP(1 << comp_index)) ? true : false; +} + +/** + * \brief Clears RTC compare match flag. + * + * Clears the compare flag. The compare flag is set when there is a compare + * match between the counter and the compare. + * + * \note Compare 4 and 5 are only available in 16-bit mode. + * + * \param[in,out] module Pointer to the software instance struct + * \param[in] comp_index Index of compare to check current flag + * + * \return Status indicating if flag was successfully cleared. + * \retval STATUS_OK If flag was successfully cleared + * \retval STATUS_ERR_INVALID_ARG If invalid argument(s) were provided + * \retval STATUS_ERR_BAD_FORMAT If the module was not initialized in a mode + */ +enum status_code rtc_count_clear_compare_match( + struct rtc_module *const module, + const enum rtc_count_compare comp_index) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + Rtc *const rtc_module = module->hw; + + /* Check sanity. */ + switch (module->mode){ + case RTC_COUNT_MODE_32BIT: + /* Check sanity for 32-bit mode. */ + if (comp_index > RTC_COMP32_NUM) { + return STATUS_ERR_INVALID_ARG; + } + + break; + + case RTC_COUNT_MODE_16BIT: + /* Check sanity for 16-bit mode. */ + if (comp_index > RTC_NUM_OF_COMP16) { + return STATUS_ERR_INVALID_ARG; + } + + break; + + default: + Assert(false); + return STATUS_ERR_BAD_FORMAT; + } + + /* Clear INTFLAG. */ + rtc_module->MODE0.INTFLAG.reg = RTC_MODE1_INTFLAG_CMP(1 << comp_index); + + return STATUS_OK; +} + +/** + * \brief Calibrate for too-slow or too-fast oscillator. + * + * When used, the RTC will compensate for an inaccurate oscillator. The + * RTC module will add or subtract cycles from the RTC prescaler to adjust the + * frequency in approximately 1 PPM steps. The provided correction value should + * be between 0 and 127, allowing for a maximum 127 PPM correction. + * + * If no correction is needed, set value to zero. + * + * \note Can only be used when the RTC is operated in 1Hz. + * + * \param[in,out] module Pointer to the software instance struct + * \param[in] value Ranging from -127 to 127 used for the correction + * + * \return Status of the calibration procedure. + * \retval STATUS_OK If calibration was executed correctly + * \retval STATUS_ERR_INVALID_ARG If invalid argument(s) were provided + */ +enum status_code rtc_count_frequency_correction( + struct rtc_module *const module, + const int8_t value) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + Rtc *const rtc_module = module->hw; + + /* Check if valid argument. */ + if (abs(value) > 0x7F) { + /* Value bigger than allowed, return invalid argument. */ + return STATUS_ERR_INVALID_ARG; + } + + uint32_t new_correction_value; + + /* Load the new correction value as a positive value, sign added later */ + new_correction_value = abs(value); + + /* Convert to positive value and adjust register sign bit. */ + if (value < 0) { + new_correction_value |= RTC_FREQCORR_SIGN; + } + + while (rtc_count_is_syncing(module)) { + /* Wait for synchronization */ + } + + /* Set value. */ + rtc_module->MODE0.FREQCORR.reg = new_correction_value; + + while (rtc_count_is_syncing(module)) { + /* Wait for synchronization */ + } + + return STATUS_OK; +} + +#ifdef FEATURE_RTC_TAMPER_DETECTION +/** + * \brief Applies the given configuration. + * + * Sets the configurations given from the configuration structure to the + * RTC tamper and it should be called before RTC module enable. + * + * \param[in,out] module Pointer to the software instance struct + * \param[in] config Pointer to the configuration structure + * + * \return Status of the configuration procedure. + * \retval STATUS_OK RTC configurations was set successfully + * \note If tamper input configured as active layer protection, RTC prescaler + * output automatically enabled in the function. + */ +enum status_code rtc_tamper_set_config ( + struct rtc_module *const module, + struct rtc_tamper_config *const tamper_cfg) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + Assert(tamper_cfg); + + Rtc *const rtc_module = module->hw; + uint16_t ctrl_b = 0; + + /* Configure enable backup and GP register reset on tamper or not. */ + if(tamper_cfg->bkup_reset_on_tamper) { + rtc_module->MODE0.CTRLA.reg |= RTC_MODE0_CTRLA_BKTRST; + } else { + rtc_module->MODE0.CTRLA.reg &= ~RTC_MODE0_CTRLA_BKTRST; + } + + if (tamper_cfg->gp_reset_on_tamper) { + rtc_module->MODE0.CTRLA.reg |= RTC_MODE0_CTRLA_GPTRST; + } else { + rtc_module->MODE0.CTRLA.reg &= ~RTC_MODE0_CTRLA_GPTRST; + } + + /* Configure tamper detection of frequency and debounce setting. */ + ctrl_b = tamper_cfg->actl_freq_div | tamper_cfg->deb_freq_div; + if(tamper_cfg->deb_seq == RTC_TAMPER_DEBOUNCE_ASYNC) { + ctrl_b |= RTC_MODE0_CTRLB_DEBASYNC; + } else if (tamper_cfg->deb_seq == RTC_TAMPER_DEBOUNCE_MAJORITY) { + ctrl_b |= RTC_MODE0_CTRLB_DEBMAJ; + } + if(tamper_cfg->dma_tamper_enable) { + ctrl_b |= RTC_MODE0_CTRLB_DMAEN; + } + if (tamper_cfg->gp0_enable) { + ctrl_b |= RTC_MODE0_CTRLB_GP0EN; + } + + /* Configure tamper input. */ + volatile RTC_TAMPCTRL_Type *tamper_ctrl = &(rtc_module->MODE0.TAMPCTRL); + + struct rtc_tamper_input_config in_cfg; + for (uint8_t tamper_id = 0; tamper_id < RTC_TAMPER_NUM; tamper_id++) { + in_cfg = tamper_cfg->in_cfg[tamper_id]; + + if(in_cfg.action == RTC_TAMPER_INPUT_ACTION_ACTL) { + ctrl_b |= RTC_MODE0_CTRLB_RTCOUT; + } + + switch(tamper_id) { + case 0: + tamper_ctrl->bit.IN0ACT = in_cfg.action; + tamper_ctrl->bit.TAMLVL0 = in_cfg.level; + tamper_ctrl->bit.DEBNC0 = in_cfg.debounce_enable; + break; + case 1: + tamper_ctrl->bit.IN1ACT = in_cfg.action; + tamper_ctrl->bit.TAMLVL1 = in_cfg.level; + tamper_ctrl->bit.DEBNC1 = in_cfg.debounce_enable; + break; + case 2: + tamper_ctrl->bit.IN2ACT = in_cfg.action; + tamper_ctrl->bit.TAMLVL2 = in_cfg.level; + tamper_ctrl->bit.DEBNC2 = in_cfg.debounce_enable; + break; + case 3: + tamper_ctrl->bit.IN3ACT = in_cfg.action; + tamper_ctrl->bit.TAMLVL3 = in_cfg.level; + tamper_ctrl->bit.DEBNC3 = in_cfg.debounce_enable; + break; + case 4: + tamper_ctrl->bit.IN4ACT = in_cfg.action; + tamper_ctrl->bit.TAMLVL4 = in_cfg.level; + tamper_ctrl->bit.DEBNC4 = in_cfg.debounce_enable; + break; + default: + Assert(false); + break; + } + } + + rtc_module->MODE0.CTRLB.reg = ctrl_b; + + /* Return status OK if everything was configured. */ + return STATUS_OK; +} + +/** + * \brief Get the tamper stamp value. + * + * \param[in,out] module Pointer to the software instance struct + * + * \return The current tamper stamp value as a 32-bit unsigned integer. + */ +uint32_t rtc_tamper_get_stamp (struct rtc_module *const module) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + Rtc *const rtc_module = module->hw; + + /* Initialize return value. */ + uint32_t tamper_stamp = 0; + + while (rtc_count_is_syncing(module)) { + /* Wait for synchronization */ + } + + /* Read value based on mode. */ + switch (module->mode) { + case RTC_COUNT_MODE_32BIT: + /* Return stamp value in 32-bit mode. */ + tamper_stamp = rtc_module->MODE0.TIMESTAMP.reg; + + break; + + case RTC_COUNT_MODE_16BIT: + /* Return stamp value in 16-bit mode. */ + tamper_stamp = (uint32_t)rtc_module->MODE1.TIMESTAMP.reg; + + break; + + default: + Assert(false); + break; + } + + return tamper_stamp; +} + +#endif diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/rtc/rtc_sam_l_c/rtc_count_interrupt.c b/src/boards/mcu/samr34/ASF/sam0/drivers/rtc/rtc_sam_l_c/rtc_count_interrupt.c new file mode 100644 index 000000000..9559a5ddc --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/rtc/rtc_sam_l_c/rtc_count_interrupt.c @@ -0,0 +1,355 @@ +/** + * \file + * + * \brief SAM RTC Driver (Count Interrupt Mode) + * + * Copyright (c) 2013-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#include "rtc_count_interrupt.h" + +extern struct rtc_module *_rtc_instance[RTC_INST_NUM]; + +/** + * \brief Registers callback for the specified callback type. + * + * Associates the given callback function with the + * specified callback type. + * To enable the callback, the \ref rtc_count_enable_callback function + * must be used. + * + * \param[in,out] module Pointer to the software instance struct + * \param[in] callback Pointer to the function desired for the specified + * callback + * \param[in] callback_type Callback type to register + * + * \return Status of registering callback. + * \retval STATUS_OK Registering was done successfully + * \retval STATUS_ERR_INVALID_ARG If trying to register a callback not available + */ +enum status_code rtc_count_register_callback( + struct rtc_module *const module, + rtc_count_callback_t callback, + enum rtc_count_callback callback_type) +{ + + enum status_code status = STATUS_OK; + + /* Overflow callback */ + if (callback_type == RTC_COUNT_CALLBACK_OVERFLOW +#ifdef FEATURE_RTC_TAMPER_DETECTION + || callback_type == RTC_COUNT_CALLBACK_TAMPER +#endif + || (callback_type >= RTC_COUNT_CALLBACK_PERIODIC_INTERVAL_0 + && callback_type <= RTC_COUNT_CALLBACK_PERIODIC_INTERVAL_7)) { + status = STATUS_OK; + } else { + /* Make sure callback type can be registered */ + switch (module->mode) { + case RTC_COUNT_MODE_32BIT: + /* Check sanity for 32-bit mode. */ + if (callback_type > (RTC_COMP32_NUM + RTC_PER_NUM)) { + status = STATUS_ERR_INVALID_ARG; + } + + break; + case RTC_COUNT_MODE_16BIT: + /* Check sanity for 16-bit mode. */ + if (callback_type > (RTC_NUM_OF_COMP16 + RTC_PER_NUM)) { + status = STATUS_ERR_INVALID_ARG; + } + break; + default: + status = STATUS_ERR_INVALID_ARG; + } + } + + if (status == STATUS_OK) { + /* Register callback */ + module->callbacks[callback_type] = callback; + /* Set corresponding bit to set callback as registered */ + module->registered_callback |= (1 << callback_type); + } + + return status; +} + +/** + * \brief Unregisters callback for the specified callback type. + * + * When called, the currently registered callback for the given callback type + * will be removed. + * + * \param[in,out] module Pointer to the software instance struct + * \param[in] callback_type Specifies the callback type to unregister + * + * \return Status of unregistering callback. + * \retval STATUS_OK Unregistering was done successfully + * \retval STATUS_ERR_INVALID_ARG If trying to unregister a callback not available + */ +enum status_code rtc_count_unregister_callback( + struct rtc_module *const module, + enum rtc_count_callback callback_type) +{ + enum status_code status = STATUS_OK; + + /* Overflow callback */ + if (callback_type == RTC_COUNT_CALLBACK_OVERFLOW +#ifdef FEATURE_RTC_TAMPER_DETECTION + || callback_type == RTC_COUNT_CALLBACK_TAMPER +#endif + || (callback_type >= RTC_COUNT_CALLBACK_PERIODIC_INTERVAL_0 + && callback_type <= RTC_COUNT_CALLBACK_PERIODIC_INTERVAL_7)) { + status = STATUS_OK; + } else { + /* Make sure callback type can be unregistered */ + switch (module->mode) { + case RTC_COUNT_MODE_32BIT: + /* Check sanity for 32-bit mode. */ + if (callback_type > (RTC_COMP32_NUM + RTC_PER_NUM)) { + status = STATUS_ERR_INVALID_ARG; + } + break; + case RTC_COUNT_MODE_16BIT: + /* Check sanity for 16-bit mode. */ + if (callback_type > (RTC_NUM_OF_COMP16 + RTC_PER_NUM)) { + status = STATUS_ERR_INVALID_ARG; + } + break; + default: + status = STATUS_ERR_INVALID_ARG; + } + } + if (status == STATUS_OK) { + /* Unregister callback */ + module->callbacks[callback_type] = NULL; + + /* Clear corresponding bit to set callback as unregistered */ + module->registered_callback &= ~(1 << callback_type); + } + return status; +} + +/** + * \brief Enables callback. + * + * Enables the callback specified by the callback_type. + * + * \param[in,out] module Pointer to the software instance struct + * \param[in] callback_type Callback type to enable + */ +void rtc_count_enable_callback( + struct rtc_module *const module, + enum rtc_count_callback callback_type) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + Rtc *const rtc_module = module->hw; + + if (callback_type == RTC_COUNT_CALLBACK_OVERFLOW) { + rtc_module->MODE0.INTENSET.reg = RTC_MODE0_INTFLAG_OVF; +#ifdef FEATURE_RTC_TAMPER_DETECTION + } else if (callback_type == RTC_COUNT_CALLBACK_TAMPER) { + rtc_module->MODE0.INTENSET.reg = RTC_MODE0_INTFLAG_TAMPER; +#endif + } else if (callback_type >= RTC_COUNT_CALLBACK_PERIODIC_INTERVAL_0 + && callback_type <= RTC_COUNT_CALLBACK_PERIODIC_INTERVAL_7) { + rtc_module->MODE0.INTENSET.reg = RTC_MODE1_INTFLAG_PER(1 << callback_type); + }else { + rtc_module->MODE0.INTENSET.reg = RTC_MODE1_INTFLAG_CMP(1 << (callback_type - RTC_PER_NUM)); + } + /* Mark callback as enabled. */ + module->enabled_callback |= (1 << callback_type); +} + +/** + * \brief Disables callback. + * + * Disables the callback specified by the callback_type. + * + * \param[in,out] module Pointer to the software instance struct + * \param[in] callback_type Callback type to disable + */ +void rtc_count_disable_callback( + struct rtc_module *const module, + enum rtc_count_callback callback_type) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + Rtc *const rtc_module = module->hw; + + /* Disable interrupt */ + if (callback_type == RTC_COUNT_CALLBACK_OVERFLOW) { + rtc_module->MODE0.INTENCLR.reg = RTC_MODE0_INTFLAG_OVF; +#ifdef FEATURE_RTC_TAMPER_DETECTION + } else if (callback_type == RTC_COUNT_CALLBACK_TAMPER) { + rtc_module->MODE0.INTENCLR.reg = RTC_MODE0_INTFLAG_TAMPER; +#endif + } else if(callback_type >= RTC_COUNT_CALLBACK_PERIODIC_INTERVAL_0 + && callback_type <= RTC_COUNT_CALLBACK_PERIODIC_INTERVAL_7){ + rtc_module->MODE0.INTENCLR.reg = RTC_MODE1_INTFLAG_PER(1 << callback_type);; + }else { + rtc_module->MODE0.INTENCLR.reg = RTC_MODE1_INTFLAG_CMP(1 << (callback_type - RTC_PER_NUM)); + } + + /* Mark callback as disabled. */ + module->enabled_callback &= ~(1 << callback_type); +} + +/** + * \internal Interrupt handler for RTC + * + * \param [in] instance_index Default value 0 + */ +static void _rtc_interrupt_handler(const uint32_t instance_index) +{ + struct rtc_module *module = _rtc_instance[instance_index]; + + Rtc *const rtc_module = module->hw; + + /* Combine callback registered and enabled masks */ + uint16_t callback_mask = module->enabled_callback; + callback_mask &= module->registered_callback; + + /* Read and mask interrupt flag register */ + uint16_t interrupt_status = rtc_module->MODE0.INTFLAG.reg; + interrupt_status &= rtc_module->MODE0.INTENSET.reg; + + if (interrupt_status & RTC_MODE0_INTFLAG_OVF) { + /* Overflow interrupt */ + if (callback_mask & (1 << RTC_COUNT_CALLBACK_OVERFLOW)) { + module->callbacks[RTC_COUNT_CALLBACK_OVERFLOW](); + } + + /* Clear interrupt flag */ + rtc_module->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_OVF; +#ifdef FEATURE_RTC_TAMPER_DETECTION + } else if (interrupt_status & RTC_MODE0_INTFLAG_TAMPER) { + /* Tamper interrupt */ + if (callback_mask & (1 << RTC_COUNT_CALLBACK_TAMPER)) { + module->callbacks[RTC_COUNT_CALLBACK_TAMPER](); + } + + /* Clear interrupt flag */ + rtc_module->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_TAMPER; +#endif + + } else if (interrupt_status & RTC_MODE1_INTFLAG_PER(0xff)) { + uint8_t i = 0; + for ( i = 0;i < RTC_PER_NUM;i++) { + if ((interrupt_status & RTC_MODE1_INTFLAG_PER(1 << i)) + && (callback_mask & (1 << i))) { + module->callbacks[i](); + } + + /* Clear interrupt flag */ + rtc_module->MODE0.INTFLAG.reg = RTC_MODE1_INTFLAG_PER(1<callbacks[RTC_COUNT_CALLBACK_COMPARE_0](); + } + /* Clear interrupt flag */ + rtc_module->MODE0.INTFLAG.reg = RTC_MODE1_INTFLAG_CMP(1 << 0); + + } else if (interrupt_status & RTC_MODE1_INTFLAG_CMP(1 << 1)) { + #if (RTC_NUM_OF_COMP16 > 1) || defined(__DOXYGEN__) + /* Compare 1 interrupt */ + if (callback_mask & (1 << RTC_COUNT_CALLBACK_COMPARE_1)) { + module->callbacks[RTC_COUNT_CALLBACK_COMPARE_1](); + } + /* Clear interrupt flag */ + rtc_module->MODE0.INTFLAG.reg = RTC_MODE1_INTFLAG_CMP(1 << 1); + #endif + + } else if (interrupt_status & RTC_MODE1_INTFLAG_CMP(1 << 2)) { + #if (RTC_NUM_OF_COMP16 > 2) || defined(__DOXYGEN__) + /* Compare 2 interrupt */ + if (callback_mask & (1 << RTC_COUNT_CALLBACK_COMPARE_2)) { + module->callbacks[RTC_COUNT_CALLBACK_COMPARE_2](); + } + /* Clear interrupt flag */ + rtc_module->MODE0.INTFLAG.reg = RTC_MODE1_INTFLAG_CMP(1 << 2); + #endif + + } else if (interrupt_status & RTC_MODE1_INTFLAG_CMP(1 << 3)) { + #if (RTC_NUM_OF_COMP16 > 3) || defined(__DOXYGEN__) + /* Compare 3 interrupt */ + if (callback_mask & (1 << RTC_COUNT_CALLBACK_COMPARE_3)) { + module->callbacks[RTC_COUNT_CALLBACK_COMPARE_3](); + } + /* Clear interrupt flag */ + rtc_module->MODE0.INTFLAG.reg = RTC_MODE1_INTFLAG_CMP(1 << 3); + #endif + + } else if (interrupt_status & RTC_MODE1_INTFLAG_CMP(1 << 4)) { + #if (RTC_NUM_OF_COMP16 > 4) || defined(__DOXYGEN__) + /* Compare 4 interrupt */ + if (callback_mask & (1 << RTC_COUNT_CALLBACK_COMPARE_4)) { + module->callbacks[RTC_COUNT_CALLBACK_COMPARE_4](); + } + /* Clear interrupt flag */ + rtc_module->MODE0.INTFLAG.reg = RTC_MODE1_INTFLAG_CMP(1 << 4); + #endif + + } else if (interrupt_status & RTC_MODE1_INTFLAG_CMP(1 << 5)) { + #if (RTC_NUM_OF_COMP16 > 5) || defined(__DOXYGEN__) + /* Compare 5 interrupt */ + if (callback_mask & (1 << RTC_COUNT_CALLBACK_COMPARE_5)) { + module->callbacks[RTC_COUNT_CALLBACK_COMPARE_5](); + } + /* Clear interrupt flag */ + rtc_module->MODE0.INTFLAG.reg = RTC_MODE1_INTFLAG_CMP(1 << 5); + #endif + } +} + +/** + * \internal ISR handler for RTC + */ +#if (RTC_INST_NUM == 1) +void RTC_Handler(void) +{ + _rtc_interrupt_handler(0); +} +#elif (RTC_INST_NUM > 1) +# define _RTC_INTERRUPT_HANDLER(n, unused) \ + void RTC##n##_Handler(void) \ + { \ + _rtc_interrupt_handler(n); \ + } + +MREPEAT(RTC_INST_NUM, _RTC_INTERRUPT_HANDLER, ~) +#endif /* (RTC_INST_NUM > 1) */ \ No newline at end of file diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/rtc/rtc_tamper.h b/src/boards/mcu/samr34/ASF/sam0/drivers/rtc/rtc_tamper.h new file mode 100644 index 000000000..5bb8efd85 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/rtc/rtc_tamper.h @@ -0,0 +1,368 @@ +/** + * \file + * + * \brief SAM RTC Driver (Tamper) + * + * Copyright (c) 2015-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#ifndef RTC_TAMPER_H_INCLUDED +#define RTC_TAMPER_H_INCLUDED + +/** + * + * \section asfdoc_sam0_rtc_tamper_detect RTC Tamper Detect + * The RTC provides several selectable polarity external inputs (INn) that can be + * used for tamper detection. When detect, tamper inputs support the four actions: + * - Off + * - Wake + * - Capture + * - Active layer protection + * + * \note The Active Layer Protection is a means of detecting broken traces on the + * PCB provided by RTC. In this mode an RTC output signal is routed over critical + * components on the board and fed back to one of the RTC inputs. The input and + * output signals are compared and a tamper condition is detected when they do not match. + * + * + * Separate debouncers are embedded for each external input. The detection time + * depends on whether the debouncer operates synchronously or asynchronously, + * and whether majority detection is enabled or not. For details, refer to the section + * "Tamper Detection" of datasheet. + * \if RTC_COUNT_CALLBACK_MODE + * \addtogroup asfdoc_sam0_rtc_count_group + * \else + * \if RTC_CALENDAR_CALLBACK_MODE + * \addtogroup asfdoc_sam0_rtc_calendar_group + * \endif + * \endif + * @{ + */ + +#if defined(FEATURE_RTC_TAMPER_DETECTION) || defined(__DOXYGEN__) + +/** RTC tamper ID0 detection bitmask. */ +#define RTC_TAMPER_DETECT_ID0 (1UL << 0) +/** RTC tamper ID1 detection bitmask. */ +#define RTC_TAMPER_DETECT_ID1 (1UL << 1) +/** RTC tamper ID2 detection bitmask. */ +#define RTC_TAMPER_DETECT_ID2 (1UL << 2) +/** RTC tamper ID3 detection bitmask. */ +#define RTC_TAMPER_DETECT_ID3 (1UL << 3) +/** RTC tamper ID4 detection bitmask. */ +#define RTC_TAMPER_DETECT_ID4 (1UL << 4) +/** RTC tamper input event detection bitmask. */ +#define RTC_TAMPER_DETECT_EVT (1UL << 5) + + + +/** + * \brief RTC tamper active layer frequency divider. + * + * The available prescaler factor for the RTC clock output used during active + * layer protection. + */ +enum rtc_tamper_active_layer_freq_divider { + /** RTC active layer frequency is prescaled by a factor of 2 */ + RTC_TAMPER_ACTIVE_LAYER_FREQ_DIV_2 = RTC_MODE0_CTRLB_ACTF_DIV2, + /** RTC active layer frequency is prescaled by a factor of 4 */ + RTC_TAMPER_ACTIVE_LAYER_FREQ_DIV_4 = RTC_MODE0_CTRLB_ACTF_DIV4, + /** RTC active layer frequency is prescaled by a factor of 8 */ + RTC_TAMPER_ACTIVE_LAYER_FREQ_DIV_8 = RTC_MODE0_CTRLB_ACTF_DIV8, + /** RTC active layer frequency is prescaled by a factor of 16 */ + RTC_TAMPER_ACTIVE_LAYER_FREQ_DIV_16 = RTC_MODE0_CTRLB_ACTF_DIV16, + /** RTC active layer frequency is prescaled by a factor of 32 */ + RTC_TAMPER_ACTIVE_LAYER_FREQ_DIV_32 = RTC_MODE0_CTRLB_ACTF_DIV32, + /** RTC active layer frequency is prescaled by a factor of 64 */ + RTC_TAMPER_ACTIVE_LAYER_FREQ_DIV_64 = RTC_MODE0_CTRLB_ACTF_DIV64, + /** RTC active layer frequency is prescaled by a factor of 128 */ + RTC_TAMPER_ACTIVE_LAYER_FREQ_DIV_128 = RTC_MODE0_CTRLB_ACTF_DIV128, + /** RTC active layer frequency is prescaled by a factor of 256 */ + RTC_TAMPER_ACTIVE_LAYER_FREQ_DIV_256 = RTC_MODE0_CTRLB_ACTF_DIV256, +}; + +/** + * \brief RTC tamper debounce frequency divider. + * + * The available prescaler factor for the input debouncers. + */ +enum rtc_tamper_debounce_freq_divider { + /** RTC debounce frequency is prescaled by a factor of 2 */ + RTC_TAMPER_DEBOUNCE_FREQ_DIV_2 = RTC_MODE0_CTRLB_DEBF_DIV2, + /** RTC debounce frequency is prescaled by a factor of 4 */ + RTC_TAMPER_DEBOUNCE_FREQ_DIV_4 = RTC_MODE0_CTRLB_DEBF_DIV4, + /** RTC debounce frequency is prescaled by a factor of 8 */ + RTC_TAMPER_DEBOUNCE_FREQ_DIV_8 = RTC_MODE0_CTRLB_DEBF_DIV8, + /** RTC debounce frequency is prescaled by a factor of 16 */ + RTC_TAMPER_DEBOUNCE_FREQ_DIV_16 = RTC_MODE0_CTRLB_DEBF_DIV16, + /** RTC debounce frequency is prescaled by a factor of 32 */ + RTC_TAMPER_DEBOUNCE_FREQ_DIV_32 = RTC_MODE0_CTRLB_DEBF_DIV32, + /** RTC debounce frequency is prescaled by a factor of 64 */ + RTC_TAMPER_DEBOUNCE_FREQ_DIV_64 = RTC_MODE0_CTRLB_DEBF_DIV64, + /** RTC debounce frequency is prescaled by a factor of 128 */ + RTC_TAMPER_DEBOUNCE_FREQ_DIV_128 = RTC_MODE0_CTRLB_DEBF_DIV128, + /** RTC debounce frequency is prescaled by a factor of 256 */ + RTC_TAMPER_DEBOUNCE_FREQ_DIV_256 = RTC_MODE0_CTRLB_DEBF_DIV256, +}; + +/** + * \brief RTC tamper input action. + * + * The available action taken by the tamper input. + */ +enum rtc_tamper_input_action { + /** RTC tamper input action is disabled */ + RTC_TAMPER_INPUT_ACTION_OFF = RTC_TAMPCTRL_IN0ACT_OFF, + /** RTC tamper input action is wake and set tamper flag */ + RTC_TAMPER_INPUT_ACTION_WAKE = RTC_TAMPCTRL_IN0ACT_WAKE, + /** RTC tamper input action is capture timestamp and set tamper flag */ + RTC_TAMPER_INPUT_ACTION_CAPTURE = RTC_TAMPCTRL_IN0ACT_CAPTURE, + /** RTC tamper input action is compare IN to OUT, when a mismatch occurs, + * capture timestamp and set tamper flag */ + RTC_TAMPER_INPUT_ACTION_ACTL = RTC_TAMPCTRL_IN0ACT_ACTL, +}; + +/** + * \brief RTC tamper input level select. + * + * The available edge condition for tamper INn level select. + */ +enum rtc_tamper_level_sel { + /** A falling edge condition will be detected on Tamper input */ + RTC_TAMPER_LEVEL_FALLING = (0), + /** A rising edge condition will be detected on Tamper input */ + RTC_TAMPER_LEVEL_RISING = (1), +}; + +/** + * \brief RTC tamper debounce sequential. + * + * The available sequential for tamper debounce. + */ +enum rtc_tamper_debounce_seq { + /** Tamper input detect edge with synchronous stability debounce */ + RTC_TAMPER_DEBOUNCE_SYNC, + /** Tamper input detect edge with asynchronous stability debounce */ + RTC_TAMPER_DEBOUNCE_ASYNC, + /** Tamper input detect edge with majority debounce */ + RTC_TAMPER_DEBOUNCE_MAJORITY, +}; + +/** + * \brief RTC tamper input configuration structure. + * + * The configuration structure for tamper INn. + */ +struct rtc_tamper_input_config { + /** Debounce enable */ + bool debounce_enable; + /** Tamper level select */ + enum rtc_tamper_level_sel level; + /** Tamper input action */ + enum rtc_tamper_input_action action; +}; + +/** + * \brief RTC Tamper configuration structure. + * + * The configuration structure for the RTC tamper. This structure should + * be initialized using the \ref rtc_tamper_get_config_defaults() before any + * user configurations are set. + */ +struct rtc_tamper_config { + /** Backup register reset on tamper enable */ + bool bkup_reset_on_tamper; + /** GP register reset on tamper enable */ + bool gp_reset_on_tamper; + /** Active layer frequency */ + enum rtc_tamper_active_layer_freq_divider actl_freq_div; + /** Debounce frequency */ + enum rtc_tamper_debounce_freq_divider deb_freq_div; + /** Debounce sequential */ + enum rtc_tamper_debounce_seq deb_seq; + /** DMA on tamper enable */ + bool dma_tamper_enable; + /** General Purpose 0/1 Enable */ + bool gp0_enable; + /** Tamper IN configuration */ + struct rtc_tamper_input_config in_cfg[RTC_TAMPER_NUM]; +}; + +/** + * \name RTC Tamper Detection + * @{ + */ + +/** + * \brief Gets the RTC tamper default configurations. + * + * Initializes the configuration structure to default values. + * + * The default configuration is as follows: + * - Disable backup register reset on tamper + * - Disable GP register reset on tamper + * - Active layer clock divided by a factor of 8 + * - Debounce clock divided by a factor of 8 + * - Detect edge on INn with synchronous stability debouncing + * - Disable DMA on tamper + * - Enable GP register + * - Disable debouce, detect on falling edge and no action on INn + * + * \param[out] config Configuration structure to be initialized to default values. + */ +static inline void rtc_tamper_get_config_defaults( + struct rtc_tamper_config *const config) +{ + /* Sanity check argument */ + Assert(config); + + config->bkup_reset_on_tamper= false; + config->gp_reset_on_tamper = false; + config->actl_freq_div = RTC_TAMPER_ACTIVE_LAYER_FREQ_DIV_8; + config->deb_freq_div = RTC_TAMPER_DEBOUNCE_FREQ_DIV_8; + config->deb_seq = RTC_TAMPER_DEBOUNCE_SYNC; + config->dma_tamper_enable = false; + config->gp0_enable = true; + + for (uint8_t id = 0; id < RTC_TAMPER_NUM; id++) { + config->in_cfg[id].debounce_enable = false; + config->in_cfg[id].level = RTC_TAMPER_LEVEL_FALLING; + config->in_cfg[id].action = RTC_TAMPER_INPUT_ACTION_OFF; + } +} +enum status_code rtc_tamper_set_config (struct rtc_module *const module, + struct rtc_tamper_config *const tamper_cfg); + +/** + * \brief Retrieves the RTC tamper detection status. + * + * Retrieves the detection status of each input pin and the input event. + * + * \param[in] module Pointer to the RTC software instance struct + * + * \return Bitmask of detection flags. + * + * \retval RTC_TAMPER_DETECT_ID0 Tamper condition on IN0 has been detected + * \retval RTC_TAMPER_DETECT_ID1 Tamper condition on IN1 has been detected + * \retval RTC_TAMPER_DETECT_ID2 Tamper condition on IN2 has been detected + * \retval RTC_TAMPER_DETECT_ID3 Tamper condition on IN3 has been detected + * \retval RTC_TAMPER_DETECT_ID4 Tamper condition on IN4 has been detected + * \retval RTC_TAMPER_DETECT_EVT Tamper input event has been detected + */ +static inline uint32_t rtc_tamper_get_detect_flag (struct rtc_module *const module) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + uint32_t tamper_id = module->hw->MODE0.TAMPID.reg; + uint32_t detect_flags = 0; + + if (tamper_id & RTC_TAMPID_TAMPID0) { + detect_flags |= RTC_TAMPER_DETECT_ID0; + } + + if (tamper_id & RTC_TAMPID_TAMPID1) { + detect_flags |= RTC_TAMPER_DETECT_ID1; + } + + if (tamper_id & RTC_TAMPID_TAMPID2) { + detect_flags |= RTC_TAMPER_DETECT_ID2; + } + + if (tamper_id & RTC_TAMPID_TAMPID3) { + detect_flags |= RTC_TAMPER_DETECT_ID3; + } + + if (tamper_id & RTC_TAMPID_TAMPID4) { + detect_flags |= RTC_TAMPER_DETECT_ID4; + } + + if (tamper_id & RTC_TAMPID_TAMPEVT) { + detect_flags |= RTC_TAMPER_DETECT_EVT; + } + + return detect_flags; +} + +/** + * \brief Clears RTC tamper detection flag. + * + * Clears the given detection flag of the module. + * + * \param[in] module Pointer to the TC software instance struct + * \param[in] detect_flags Bitmask of detection flags + */ +static inline void rtc_tamper_clear_detect_flag( + struct rtc_module *const module, + const uint32_t detect_flags) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + uint32_t tamper_id = 0; + + if (detect_flags & RTC_TAMPER_DETECT_ID0) { + tamper_id |= RTC_TAMPID_TAMPID0; + } + + if (detect_flags & RTC_TAMPER_DETECT_ID1) { + tamper_id |= RTC_TAMPID_TAMPID1; + } + + if (detect_flags & RTC_TAMPER_DETECT_ID2) { + tamper_id |= RTC_TAMPID_TAMPID2; + } + + if (detect_flags & RTC_TAMPER_DETECT_ID3) { + tamper_id |= RTC_TAMPID_TAMPID3; + } + + if (detect_flags & RTC_TAMPER_DETECT_ID4) { + tamper_id |= RTC_TAMPID_TAMPID4; + } + + if (detect_flags & RTC_TAMPER_DETECT_EVT) { + tamper_id |= RTC_TAMPID_TAMPEVT; + } + + module->hw->MODE0.TAMPID.reg = tamper_id; + +} + +/** @} */ + +#endif +/** @} */ + + +#endif /* RTC_TAMPER_H_INCLUDED */ \ No newline at end of file diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/i2c/i2c_common.h b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/i2c/i2c_common.h new file mode 100644 index 000000000..62cdb6ecf --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/i2c/i2c_common.h @@ -0,0 +1,607 @@ +/** + * \file + * + * \brief SAM SERCOM I2C Common Driver + * + * Copyright (c) 2012-2020 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#ifndef I2C_COMMON_H_INCLUDED +#define I2C_COMMON_H_INCLUDED + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \if (I2C_MASTER_MODE && I2C_SLAVE_MODE) + * \defgroup asfdoc_sam0_sercom_i2c_group SAM I2C (SERCOM I2C) Driver + * \elseif I2C_MASTER_MODE + * \defgroup asfdoc_sam0_sercom_i2c_group SAM I2C Master Mode (SERCOM I2C) Driver + * \elseif I2C_SLAVE_MODE + * \defgroup asfdoc_sam0_sercom_i2c_group SAM I2C Slave Mode (SERCOM I2C) Driver + * \endif + * + * This driver for Atmel® | SMART ARM®-based microcontrollers provides + * an interface for the configuration and management of the device's SERCOM + * I2C module, for the transfer of data via an I2C bus. + * The following driver API modes are covered by this manual: + * + * \if I2C_MASTER_MODE + * - Master Mode Polled APIs + * \endif + * \if I2C_MASTER_CALLBACK_MODE + * - Master Mode Callback APIs + * \endif + * \if I2C_SLAVE_MODE + * - Slave Mode Polled APIs + * \endif + * \if I2C_SLAVE_CALLBACK_MODE + * - Slave Mode Callback APIs + * \endif + * + * The following peripheral is used by this module: + * - SERCOM (Serial Communication Interface) + * + * The following devices can use this module: + * - Atmel | SMART SAM D20/D21 + * - Atmel | SMART SAM R21 + * - Atmel | SMART SAM D09/D10/D11 + * - Atmel | SMART SAM L21/L22 + * - Atmel | SMART SAM DA1 + * - Atmel | SMART SAM C20/C21 + * - Atmel | SMART SAM HA1 + * - Atmel | SMART SAM R30 + * - Atmel | SMART SAM R34 + * - Atmel | SMART SAM R35 + * + * The outline of this documentation is as follows: + * - \ref asfdoc_sam0_sercom_i2c_prerequisites + * - \ref asfdoc_sam0_sercom_i2c_overview + * - \ref asfdoc_sam0_sercom_i2c_special_considerations + * - \ref asfdoc_sam0_sercom_i2c_extra + * - \ref asfdoc_sam0_sercom_i2c_examples + * - \ref asfdoc_sam0_sercom_i2c_api_overview + * + * \section asfdoc_sam0_sercom_i2c_prerequisites Prerequisites + * There are no prerequisites. + * + * \section asfdoc_sam0_sercom_i2c_overview Module Overview + * The outline of this section is as follows: + * - \ref asfdoc_sam0_sercom_i2c_module_features + * - \ref asfdoc_sam0_sercom_i2c_functional_desc + * - \ref asfdoc_sam0_sercom_i2c_bus_topology + * - \ref asfdoc_sam0_sercom_i2c_transactions + * - \ref asfdoc_sam0_sercom_i2c_multi_master + * - \ref asfdoc_sam0_sercom_i2c_bus_states + * - \ref asfdoc_sam0_sercom_i2c_timeout + * - \ref asfdoc_sam0_sercom_i2c_sleep_modes + * + * \subsection asfdoc_sam0_sercom_i2c_module_features Driver Feature Macro Definition + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Driver Feature MacroSupported devices
FEATURE_I2C_FAST_MODE_PLUS_AND_HIGH_SPEEDSAM D21/R21/D10/D11/L21/L22/DA1/C20/C21/HA1/R34/R35
FEATURE_I2C_10_BIT_ADDRESSSAM D21/R21/D10/D11/L21/L22/DA1/C20/C21/HA1/R34/R35
FEATURE_I2C_SCL_STRETCH_MODESAM D21/R21/D10/D11/L21/L22/DA1/C20/C21/HA1/R34/R35
FEATURE_I2C_SCL_EXTEND_TIMEOUTSAM D21/R21/D10/D11/L21/L22/DA1/C20/C21/HA1/R34/R35
+ * \note The specific features are only available in the driver when the selected + * device supports those features. + * \note When using the I2C high-speed mode for off-board communication, + * there are various high frequency interference, which can lead to distortion of the signals + * and communication failure. When using Xplained Pro boards in order to test I2C high-speed + * communication, the following recommendation should be followed: + * - Use the SDA-line on PA08 and SCL-line on PA09 for both boards. This will provide stronger + * pull-ups on both SDA and SCL. + * - The SCL should not be higher than 1.5MHz. + * + * \subsection asfdoc_sam0_sercom_i2c_functional_desc Functional Description + * The I2C provides a simple two-wire bidirectional bus consisting of a + * wired-AND type serial clock line (SCL) and a wired-AND type serial data line + * (SDA). + * + * The I2C bus provides a simple, but efficient method of interconnecting + * multiple master and slave devices. An arbitration mechanism is provided for + * resolving bus ownership between masters, as only one master device may own + * the bus at any given time. The arbitration mechanism relies on the wired-AND + * connections to avoid bus drivers short-circuiting. + * + * A unique address is assigned to all slave devices connected to the bus. A + * device can contain both master and slave logic, and can emulate multiple + * slave devices by responding to more than one address. + * + * \subsection asfdoc_sam0_sercom_i2c_bus_topology Bus Topology + * The I2C bus topology is illustrated in + * \ref asfdoc_sam0_sercom_i2c_bus_topology_figure "the figure below". The pull-up + * resistors (Rs) will provide a high level on the bus lines when none of the + * I2C devices are driving the bus. These are optional, and can be + * replaced with a constant current source. + * + * \anchor asfdoc_sam0_sercom_i2c_bus_topology_figure + * \image html bus_topology.svg "I2C Bus Topology" Width=100% + * + * \subsection asfdoc_sam0_sercom_i2c_transactions Transactions + * The I2C standard defines three fundamental transaction formats: + * - Master Write + * - The master transmits data packets to the slave after addressing it + * - Master Read + * - The slave transmits data packets to the master after being addressed + * - Combined Read/Write + * - A combined transaction consists of several write and read transactions + * + * A data transfer starts with the master issuing a \b Start condition on the + * bus, followed by the address of the slave together with a bit to indicate + * whether the master wants to read from or write to the slave. + * The addressed slave must respond to this by sending an \b ACK back to the + * master. + * + * After this, data packets are sent from the master or slave, according to the + * read/write bit. Each packet must be acknowledged (ACK) or not + * acknowledged (NACK) by the receiver. + * + * If a slave responds with a NACK, the master must assume that the slave + * cannot receive any more data and cancel the write operation. + * + * The master completes a transaction by issuing a \b Stop condition. + * + * A master can issue multiple \b Start conditions during a transaction; this + * is then called a \b Repeated \b Start condition. + * + * \subsubsection asfdoc_sam0_sercom_i2c_address_packets Address Packets + * The slave address consists of seven bits. The 8th bit in the transfer + * determines the data direction (read or write). An address packet always + * succeeds a \b Start or \b Repeated \b Start condition. The 8th bit is handled + * in the driver, and the user will only have to provide the 7-bit address. + * + * \subsubsection asfdoc_sam0_sercom_i2c_data_packets Data Packets + * Data packets are nine bits long, consisting of one 8-bit data byte, and an + * acknowledgement bit. Data packets follow either an address packet or another + * data packet on the bus. + * + * \subsubsection asfdoc_sam0_sercom_i2c_trans_examples Transaction Examples + * The gray bits in the following examples are sent from master to slave, and + * the white bits are sent from slave to master. + * Example of a read transaction is shown in + * \ref asfdoc_sam0_sercom_i2c_trans_examples_i2c_read "the figure below". Here, the + * master first issues a \b Start condition and gets ownership of the bus. An + * address packet with the direction flag set to read is then sent and + * acknowledged by the slave. Then the slave sends one data packet which is + * acknowledged by the master. The slave sends another packet, which is not + * acknowledged by the master and indicates that the master will terminate the + * transaction. In the end, the transaction is terminated by the master issuing + * a \b Stop condition. + * + * \anchor asfdoc_sam0_sercom_i2c_trans_examples_i2c_read + * \image html i2c_read.svg "I2C Packet Read" Width=100% + * + * Example of a write transaction is shown in + * \ref asfdoc_sam0_sercom_i2c_trans_examples_i2c_write "the figure below". Here, the + * master first issues a \b Start condition and gets ownership of the bus. An + * address packet with the dir flag set to write is then sent and acknowledged + * by the slave. Then the master sends two data packets, each acknowledged by + * the slave. In the end, the transaction is terminated by the master issuing + * a \b Stop condition. + * + * \anchor asfdoc_sam0_sercom_i2c_trans_examples_i2c_write + * \image html i2c_write.svg "I2C Packet Write" Width=100% + * + * \subsubsection asfdoc_sam0_sercom_i2c_packet_timeout Packet Timeout + * When a master sends an I2C packet, there is no way of + * being sure that a slave will acknowledge the packet. To avoid stalling the + * device forever while waiting for an acknowledge, a user selectable timeout + * is provided in the \ref i2c_master_config struct which + * lets the driver exit a read or write operation after the specified time. + * The function will then return the STATUS_ERR_TIMEOUT flag. + * + * This is also the case for the slave when using the functions postfixed + * \c _wait. + * + * The time before the timeout occurs, will be the same as + * for \ref asfdoc_sam0_sercom_i2c_unknown_bus_timeout "unknown bus state" timeout. + * + * \subsubsection asfdoc_sam0_sercom_i2c_repeated_start Repeated Start + * To issue a \b Repeated \b Start, the functions postfixed \c _no_stop must be + * used. + * These functions will not send a \b Stop condition when the transfer is done, + * thus the next transfer will start with a \b Repeated \b Start. To end the + * transaction, the functions without the \c _no_stop postfix must be used + * for the last read/write. + * + * \subsection asfdoc_sam0_sercom_i2c_multi_master Multi Master + * In a multi master environment, arbitration of the bus is important, as only + * one master can own the bus at any point. + * + * \subsubsection asfdoc_sam0_sercom_i2c_arbitration Arbitration + * + * \par Clock stretching + * The serial clock line is always driven by a master device. However, all + * devices connected to the bus are allowed stretch the low period of the clock + * to slow down the overall clock frequency or to insert wait states while + * processing data. + * Both master and slave can randomly stretch the clock, which will force the + * other device into a wait-state until the clock line goes high again. + * + * \par Arbitration on the data line + * If two masters start transmitting at the same time, they will both transmit + * until one master detects that the other master is pulling the data line low. + * When this is detected, the master not pulling the line low, will stop the + * transmission and wait until the bus is idle. + * As it is the master trying to contact the slave with the lowest address that + * will get the bus ownership, this will create an arbitration scheme always + * prioritizing the slaves with the lowest address in case of a bus collision. + * + * \subsubsection asfdoc_sam0_sercom_i2c_clock_sync Clock Synchronization + * In situations where more than one master is trying to control the bus clock + * line at the same time, a clock synchronization algorithm based on the same + * principles used for clock stretching is necessary. + * + * + * \subsection asfdoc_sam0_sercom_i2c_bus_states Bus States + * As the I2C bus is limited to one transaction at the time, + * a master that wants to perform a bus transaction must wait until the bus is + * free. + * Because of this, it is necessary for all masters in a multi-master system to + * know the current status of the bus to be able to avoid conflicts and to + * ensure data integrity. + * \li \b IDLE No activity on the bus (between a \b Stop and a new \b Start + * condition) + * \li \b OWNER If the master initiates a transaction successfully + * \li \b BUSY If another master is driving the bus + * \li \b UNKNOWN If the master has recently been enabled or connected to + * the bus. Is forced to \b IDLE after given + * \ref asfdoc_sam0_sercom_i2c_unknown_bus_timeout "timeout" when + * the master module is enabled + * + * The bus state diagram can be seen in + * \ref asfdoc_sam0_sercom_i2c_bus_states_figure "the figure below". + * \li S: Start condition + * \li P: Stop condition + * \li Sr: Repeated start condition + * \anchor asfdoc_sam0_sercom_i2c_bus_states_figure + * \image html bus_state_diagram.svg "I2C Bus State Diagram" Width=100% + * + * \subsection asfdoc_sam0_sercom_i2c_timeout Bus Timing + * Inactive bus timeout for the master and SDA hold time is configurable in the + * drivers. + * + * \subsubsection asfdoc_sam0_sercom_i2c_unknown_bus_timeout Unknown Bus State Timeout + * When a master is enabled or connected to the bus, the bus state will be + * unknown until either a given timeout or a stop command has occurred. The + * timeout is configurable in the \ref i2c_master_config struct. + * The timeout time will depend on toolchain and optimization level used, as + * the timeout is a loop incrementing a value until it reaches the specified + * timeout value. + * + * \subsubsection sda_hold SDA Hold Timeout + * When using the I2C in slave mode, it will be important to + * set a SDA hold time which assures that the master will be able to pick up + * the bit sent from the slave. The SDA hold time makes sure that this is the + * case by holding the data line low for a given period after the negative edge + * on the clock. + * + * The SDA hold time is also available for the master driver, but is not a + * necessity. + * + * \subsection asfdoc_sam0_sercom_i2c_sleep_modes Operation in Sleep Modes + * The I2C module can operate in all sleep modes by setting + * the run_in_standby Boolean in the \ref i2c_master_config or + * \ref i2c_slave_config struct. + * The operation in slave and master mode is shown in + * \ref asfdoc_sam0_sercom_i2c_sleep_modes_table "the table below". + * + * \anchor asfdoc_sam0_sercom_i2c_sleep_modes_table + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
I2C Standby Operations
Run in standbySlaveMaster
falseDisabled, all reception is droppedGeneric Clock (GCLK) disabled when master is idle
trueWake on address match when enabledGCLK enabled while in sleep modes
+ * + * + * \section asfdoc_sam0_sercom_i2c_special_considerations Special Considerations + * + * \if (I2C_MASTER_CALLBACK_MODE || I2C_SLAVE_CALLBACK_MODE) + * \subsection asfdoc_sam0_sercom_i2c_common_interrupt Interrupt-driven Operation + * While an interrupt-driven operation is in progress, subsequent calls to a + * write or read operation will return the STATUS_BUSY flag, indicating that + * only one operation is allowed at any given time. + * + * To check if another transmission can be initiated, the user can either call + * another transfer operation, or use the + * \ref i2c_master_get_job_status/\ref i2c_slave_get_job_status functions + * depending on mode. + * + * If the user would like to get callback from operations while using the + * interrupt-driven driver, the callback must be registered and then enabled + * using the "register_callback" and "enable_callback" functions. + * \else + * There are no special considerations for this driver for the APIs listed in + * this document. + * \endif + * + * \section asfdoc_sam0_sercom_i2c_extra Extra Information + * For extra information, see \ref asfdoc_sam0_sercom_i2c_extra_info_page. + * This includes: + * - \ref asfdoc_sam0_sercom_i2c_acronyms + * - \ref asfdoc_sam0_sercom_i2c_extra_dependencies + * - \ref asfdoc_sam0_sercom_i2c_extra_errata + * - \ref asfdoc_sam0_sercom_i2c_extra_history + * + * \section asfdoc_sam0_sercom_i2c_examples Examples + * + * For a list of examples related to this driver, see + * \ref asfdoc_sam0_sercom_i2c_exqsg. + * + * \section asfdoc_sam0_sercom_i2c_api_overview API Overview + * @{ + */ + +/** + * \name Driver Feature Definition + * Define SERCOM I2C driver features set according to different device family. + * + * @{ + */ +#if (SAMD21) || (SAMR21) || (SAMD10) || (SAMD11) || (SAML21) || (SAMDA1) || \ + (SAMHA1) || (SAMHA0) || (SAML22) || (SAMC20) || (SAMC21) || (SAMD09) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) || defined(__DOXYGEN__) +/** Fast mode plus and high speed support. */ +# define FEATURE_I2C_FAST_MODE_PLUS_AND_HIGH_SPEED +/** 10-bit address support */ +# define FEATURE_I2C_10_BIT_ADDRESS +/** SCL stretch mode support */ +# define FEATURE_I2C_SCL_STRETCH_MODE +/** SCL extend timeout support */ +# define FEATURE_I2C_SCL_EXTEND_TIMEOUT +# define FEATURE_I2C_DMA_SUPPORT +#endif +/*@}*/ + +/** \brief Transfer direction + * + * For master: transfer direction or setting direction bit in address. + * For slave: direction of request from master. + */ +enum i2c_transfer_direction { + /** Master write operation is in progress */ + I2C_TRANSFER_WRITE = 0, + /** Master read operation is in progress */ + I2C_TRANSFER_READ = 1, +}; + +/** @} */ + +#ifdef __cplusplus +} +#endif + +/** + * \page asfdoc_sam0_sercom_i2c_extra_info_page Extra Information for SERCOM I2C Driver + * + * \section asfdoc_sam0_sercom_i2c_acronyms Acronyms + * \ref asfdoc_sam0_sercom_i2c_acronyms_table "Below" is a table listing the acronyms + * used in this module, along with their intended meanings. + * + * \anchor asfdoc_sam0_sercom_i2c_acronyms_table + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Acronyms
AcronymDescription
SDASerial Data Line
SCLSerial Clock Line
SERCOMSerial Communication Interface
DMADirect Memory Access
+ * + * \section asfdoc_sam0_sercom_i2c_extra_dependencies Dependencies + * The I2C driver has the following dependencies: + * \li \ref asfdoc_sam0_system_pinmux_group "System Pin Multiplexer Driver" + * + * + * \section asfdoc_sam0_sercom_i2c_extra_errata Errata + * There are no errata related to this driver. + * + * \section asfdoc_sam0_sercom_i2c_extra_history Module History + * \ref asfdoc_sam0_sercom_i2c_extra_history_table "Below" is an overview of the + * module history, detailing enhancements and fixes made to the module since + * its first release. The current version of this corresponds to the newest + * version listed in + * \ref asfdoc_sam0_sercom_i2c_extra_history_table "the table below". + * + * \anchor asfdoc_sam0_sercom_i2c_extra_history_table + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Module History
Changelog
+ * \li Added 10-bit addressing and high speed support in SAM D21 + * \li Separate structure i2c_packet into i2c_master_packet and i2c_slave packet + *
+ * \li Added support for SCL stretch and extended timeout hardware features in SAM D21 + * \li Added fast mode plus support in SAM D21 + *
Fixed incorrect logical mask for determining if a bus error has + * occurred in I2C Slave mode + *
Initial Release
+ */ + +/** + * \page asfdoc_sam0_sercom_i2c_exqsg Examples for SERCOM I2C Driver + * + * This is a list of the available Quick Start guides (QSGs) and example + * applications for \ref asfdoc_sam0_sercom_i2c_group. QSGs are simple examples with + * step-by-step instructions to configure and use this driver in a selection of + * use cases. Note that a QSG can be compiled as a standalone application or be + * added to the user application. + * + * \if I2C_MASTER_MODE + * - \subpage asfdoc_sam0_sercom_i2c_master_basic_use_case "Quick Start Guide for the I2C Master module - Basic Use Case" + * \endif + * \if I2C_MASTER_CALLBACK_MODE + * - \subpage asfdoc_sam0_sercom_i2c_master_callback_use_case "Quick Start Guide for the I2C Master module - Callback Use Case" + * - \subpage asfdoc_sam0_sercom_i2c_master_dma_use_case "Quick Start Guide for the I2C Master module - DMA Use Case" + * \endif + * \if I2C_SLAVE_MODE + * - \subpage asfdoc_sam0_sercom_i2c_slave_basic_use_case "Quick Start Guide for the I2C Slave module - Basic Use Case" + * \endif + * \if I2C_SLAVE_CALLBACK_MODE + * - \subpage asfdoc_sam0_sercom_i2c_slave_callback_use_case "Quick Start Guide for the I2C Slave module - Callback Use Case" + * - \subpage asfdoc_sam0_sercom_i2c_slave_dma_use_case "Quick Start Guide for the I2C Slave module - DMA Use Case" + * \endif + * + * \page asfdoc_sam0_sercom_i2c_document_revision_history Document Revision History + * + * \if (I2C_MASTER_MODE || I2C_MASTER_CALLBACK_MODE) + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Doc. Rev.DateComments
42117E12/2015Added support for SAM L21/L22, SAM DA1, SAM D09, and SAM C21
42117D12/2014Added support for 10-bit addressing and high speed in SAM D21. + * Added support for SAM R21 and SAM D10/D11.
42117C01/2014Added support for SAM D21
42117B06/2013Corrected documentation typos. Updated I2C Bus State Diagram.
42117A06/2013Initial release
+ * \else + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Doc. Rev.DateComments
42116E12/2015Added support for SAM L21/L22, SAM DA1, SAM D09, and SAM C21
42116D12/2014Added support for 10-bit addressing and high speed in SAM D21. + * Added support for SAM R21 and SAM D10/D11.
42116C01/2014Added support for SAM D21
42116B06/2013Corrected documentation typos. Updated I2C Bus State Diagram.
42116A06/2013Initial release
+ *\endif + */ + +#endif /* I2C_COMMON_H_INCLUDED */ diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/i2c/i2c_master.h b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/i2c/i2c_master.h new file mode 100644 index 000000000..ceb33263b --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/i2c/i2c_master.h @@ -0,0 +1,619 @@ +/** + * \file + * + * \brief SAM SERCOM I2C Master Driver + * + * Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#ifndef I2C_MASTER_H_INCLUDED +#define I2C_MASTER_H_INCLUDED + +#include "i2c_common.h" +#include +#include + +#if I2C_MASTER_CALLBACK_MODE == true +# include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef PINMUX_DEFAULT +# define PINMUX_DEFAULT 0 +#endif + +/** + * \addtogroup asfdoc_sam0_sercom_i2c_group + * + * @{ + */ + +/** + * \brief I2C master packet for read/write + * + * Structure to be used when transferring I2C master packets. + */ +struct i2c_master_packet { + /** Address to slave device */ + uint16_t address; + /** Length of data array */ + uint16_t data_length; + /** Data array containing all data to be transferred */ + uint8_t *data; + /** Use 10-bit addressing. Set to false if the feature is not supported by the device */ + bool ten_bit_address; + /** Use high speed transfer. Set to false if the feature is not supported by the device */ + bool high_speed; + /** High speed mode master code (0000 1XXX), valid when high_speed is true */ + uint8_t hs_master_code; +}; + +/** \brief Interrupt flags + * + * Flags used when reading or setting interrupt flags. + */ +enum i2c_master_interrupt_flag { + /** Interrupt flag used for write */ + I2C_MASTER_INTERRUPT_WRITE = 0, + /** Interrupt flag used for read */ + I2C_MASTER_INTERRUPT_READ = 1, +}; + +/** + * \brief Values for hold time after start bit. + * + * Values for the possible I2C master mode SDA internal hold times after start + * bit has been sent. + */ +enum i2c_master_start_hold_time { + /** Internal SDA hold time disabled */ + I2C_MASTER_START_HOLD_TIME_DISABLED = SERCOM_I2CM_CTRLA_SDAHOLD(0), + /** Internal SDA hold time 50ns - 100ns */ + I2C_MASTER_START_HOLD_TIME_50NS_100NS = SERCOM_I2CM_CTRLA_SDAHOLD(1), + /** Internal SDA hold time 300ns - 600ns */ + I2C_MASTER_START_HOLD_TIME_300NS_600NS = SERCOM_I2CM_CTRLA_SDAHOLD(2), + /** Internal SDA hold time 400ns - 800ns */ + I2C_MASTER_START_HOLD_TIME_400NS_800NS = SERCOM_I2CM_CTRLA_SDAHOLD(3), +}; + +/** + * \brief Values for inactive bus time-out. + * + * If the inactive bus time-out is enabled and the bus is inactive for + * longer than the time-out setting, the bus state logic will be set to idle. + */ +enum i2c_master_inactive_timeout { + /** Inactive bus time-out disabled */ + I2C_MASTER_INACTIVE_TIMEOUT_DISABLED = SERCOM_I2CM_CTRLA_INACTOUT(0), + /** Inactive bus time-out 5-6 SCL cycle time-out */ + I2C_MASTER_INACTIVE_TIMEOUT_55US = SERCOM_I2CM_CTRLA_INACTOUT(1), + /** Inactive bus time-out 10-11 SCL cycle time-out */ + I2C_MASTER_INACTIVE_TIMEOUT_105US = SERCOM_I2CM_CTRLA_INACTOUT(2), + /** Inactive bus time-out 20-21 SCL cycle time-out */ + I2C_MASTER_INACTIVE_TIMEOUT_205US = SERCOM_I2CM_CTRLA_INACTOUT(3), +}; + +/** + * \brief I2C frequencies + * + * Values for I2C speeds supported by the module. The driver + * will also support setting any other value, in which case set + * the value in the \ref i2c_master_config at desired value divided by 1000. + * + * Example: If 10KHz operation is required, give baud_rate in the configuration + * structure the value 10. + */ +enum i2c_master_baud_rate { + /** Baud rate at 100KHz (Standard-mode) */ + I2C_MASTER_BAUD_RATE_100KHZ = 100, + /** Baud rate at 400KHz (Fast-mode) */ + I2C_MASTER_BAUD_RATE_400KHZ = 400, +#ifdef FEATURE_I2C_FAST_MODE_PLUS_AND_HIGH_SPEED + /** Baud rate at 1MHz (Fast-mode Plus) */ + I2C_MASTER_BAUD_RATE_1000KHZ = 1000, + /** Baud rate at 3.4MHz (High-speed mode) */ + I2C_MASTER_BAUD_RATE_3400KHZ = 3400, +#endif +}; + +#ifdef FEATURE_I2C_FAST_MODE_PLUS_AND_HIGH_SPEED +/** + * \brief Enum for the transfer speed + * + * Enum for the transfer speed. + */ +enum i2c_master_transfer_speed { + /** Standard-mode (Sm) up to 100KHz and Fast-mode (Fm) up to 400KHz */ + I2C_MASTER_SPEED_STANDARD_AND_FAST = SERCOM_I2CM_CTRLA_SPEED(0), + /** Fast-mode Plus (Fm+) up to 1MHz */ + I2C_MASTER_SPEED_FAST_MODE_PLUS = SERCOM_I2CM_CTRLA_SPEED(1), + /** High-speed mode (Hs-mode) up to 3.4MHz */ + I2C_MASTER_SPEED_HIGH_SPEED = SERCOM_I2CM_CTRLA_SPEED(2), +}; +#endif + +#if I2C_MASTER_CALLBACK_MODE == true +/** + * \brief Callback types + * + * The available callback types for the I2C master module. + */ +enum i2c_master_callback { + /** Callback for packet write complete */ + I2C_MASTER_CALLBACK_WRITE_COMPLETE = 0, + /** Callback for packet read complete */ + I2C_MASTER_CALLBACK_READ_COMPLETE = 1, + /** Callback for error */ + I2C_MASTER_CALLBACK_ERROR = 2, +# if !defined(__DOXYGEN__) + /** Total number of callbacks */ + _I2C_MASTER_CALLBACK_N = 3, +# endif +}; + +# if !defined(__DOXYGEN__) +/* Prototype for software module */ +struct i2c_master_module; + +typedef void (*i2c_master_callback_t)( + struct i2c_master_module *const module); +# endif +#endif + +/** + * \brief SERCOM I2C Master driver software device instance structure. + * + * SERCOM I2C Master driver software instance structure, used to + * retain software state information of an associated hardware module instance. + * + * \note The fields of this structure should not be altered by the user + * application; they are reserved for module-internal use only. + */ +struct i2c_master_module { +#if !defined(__DOXYGEN__) + /** Hardware instance initialized for the struct */ + Sercom *hw; + /** Module lock */ + volatile bool locked; + /** Unknown bus state timeout */ + uint16_t unknown_bus_state_timeout; + /** Buffer write timeout value */ + uint16_t buffer_timeout; + /** If true, stop condition will be sent after a read/write */ + bool send_stop; + /** If true, nack signal will be sent after a read/write */ + bool send_nack; +# if I2C_MASTER_CALLBACK_MODE == true + /** Pointers to callback functions */ + volatile i2c_master_callback_t callbacks[_I2C_MASTER_CALLBACK_N]; + /** Mask for registered callbacks */ + volatile uint8_t registered_callback; + /** Mask for enabled callbacks */ + volatile uint8_t enabled_callback; + /** The total number of bytes to transfer */ + volatile uint16_t buffer_length; + /** + * Counter used for bytes left to send in write and to count number of + * obtained bytes in read + */ + volatile uint16_t buffer_remaining; + /** Data buffer for packet write and read */ + volatile uint8_t *buffer; + /** Save direction of async request. 1 = read, 0 = write */ + volatile enum i2c_transfer_direction transfer_direction; + /** Status for status read back in error callback */ + volatile enum status_code status; +# endif +#endif +}; + +/** + * \brief Configuration structure for the I2C Master device + * + * This is the configuration structure for the I2C Master device. It + * is used as an argument for \ref i2c_master_init to provide the desired + * configurations for the module. The structure should be initialized using the + * \ref i2c_master_get_config_defaults. + */ +struct i2c_master_config { + /** Baud rate (in KHz) for I2C operations in + * standard-mode, Fast-mode, and Fast-mode Plus Transfers, + * \ref i2c_master_baud_rate */ + uint32_t baud_rate; +#ifdef FEATURE_I2C_FAST_MODE_PLUS_AND_HIGH_SPEED + /** Baud rate (in KHz) for I2C operations in + * High-speed mode, \ref i2c_master_baud_rate */ + uint32_t baud_rate_high_speed; + /** Transfer speed mode */ + enum i2c_master_transfer_speed transfer_speed; +#endif + /** GCLK generator to use as clock source */ + enum gclk_generator generator_source; + /** Bus hold time after start signal on data line */ + enum i2c_master_start_hold_time start_hold_time; + /** Unknown bus state \ref asfdoc_sam0_sercom_i2c_unknown_bus_timeout "timeout" */ + uint16_t unknown_bus_state_timeout; + /** Timeout for packet write to wait for slave */ + uint16_t buffer_timeout; + /** Set to keep module active in sleep modes */ + bool run_in_standby; + /** PAD0 (SDA) pinmux */ + uint32_t pinmux_pad0; + /** PAD1 (SCL) pinmux */ + uint32_t pinmux_pad1; + /** Set to enable SCL low time-out */ + bool scl_low_timeout; + /** Inactive bus time out */ + enum i2c_master_inactive_timeout inactive_timeout; +#ifdef FEATURE_I2C_SCL_STRETCH_MODE + /** Set to enable SCL stretch only after ACK bit (required for high speed) */ + bool scl_stretch_only_after_ack_bit; +#endif +#ifdef FEATURE_I2C_SCL_EXTEND_TIMEOUT + /** Set to enable slave SCL low extend time-out */ + bool slave_scl_low_extend_timeout; + /** Set to enable maser SCL low extend time-out */ + bool master_scl_low_extend_timeout; +#endif + /** Get more accurate BAUD, considering rise time(required for standard-mode and Fast-mode) */ + uint16_t sda_scl_rise_time_ns; +}; + +/** + * \name Lock/Unlock + * @{ + */ + +/** + * \brief Attempt to get lock on driver instance + * + * This function checks the instance's lock, which indicates whether or not it + * is currently in use, and sets the lock if it was not already set. + * + * The purpose of this is to enable exclusive access to driver instances, so + * that, e.g., transactions by different services will not interfere with each + * other. + * + * \param[in,out] module Pointer to the driver instance to lock + * + * \retval STATUS_OK If the module was locked + * \retval STATUS_BUSY If the module was already locked + */ +static inline enum status_code i2c_master_lock( + struct i2c_master_module *const module) +{ + enum status_code status; + + system_interrupt_enter_critical_section(); + + if (module->locked) { + status = STATUS_BUSY; + } else { + module->locked = true; + status = STATUS_OK; + } + + system_interrupt_leave_critical_section(); + + return status; +} + +/** + * \brief Unlock driver instance + * + * This function clears the instance lock, indicating that it is available for + * use. + * + * \param[in,out] module Pointer to the driver instance to lock + * + * \retval STATUS_OK If the module was locked + * \retval STATUS_BUSY If the module was already locked + */ +static inline void i2c_master_unlock(struct i2c_master_module *const module) +{ + module->locked = false; +} + +/** @} */ + +/** + * \name Configuration and Initialization + * @{ + */ + +/** + * \brief Returns the synchronization status of the module + * + * Returns the synchronization status of the module. + * + * \param[in] module Pointer to software module structure + * + * \return Status of the synchronization. + * \retval true Module is busy synchronizing + * \retval false Module is not synchronizing + */ +static inline bool i2c_master_is_syncing ( + const struct i2c_master_module *const module) +{ + /* Sanity check */ + Assert(module); + Assert(module->hw); + + SercomI2cm *const i2c_hw = &(module->hw->I2CM); + +#if defined(FEATURE_SERCOM_SYNCBUSY_SCHEME_VERSION_1) + return (i2c_hw->STATUS.reg & SERCOM_I2CM_STATUS_SYNCBUSY); +#elif defined(FEATURE_SERCOM_SYNCBUSY_SCHEME_VERSION_2) + return (i2c_hw->SYNCBUSY.reg & SERCOM_I2CM_SYNCBUSY_MASK); +#else +# error Unknown SERCOM SYNCBUSY scheme! +#endif +} + +#if !defined(__DOXYGEN__) +/** + * \internal + * Wait for hardware module to sync + * + * \param[in] module Pointer to software module structure + */ +static void _i2c_master_wait_for_sync( + const struct i2c_master_module *const module) +{ + /* Sanity check */ + Assert(module); + + while (i2c_master_is_syncing(module)) { + /* Wait for I2C module to sync. */ + } +} +#endif + +/** + * \brief Gets the I2C master default configurations + * + * Use to initialize the configuration structure to known default values. + * + * The default configuration is as follows: + * - Baudrate 100KHz + * - GCLK generator 0 + * - Do not run in standby + * - Start bit hold time 300ns - 600ns + * - Buffer timeout = 65535 + * - Unknown bus status timeout = 65535 + * - Do not run in standby + * - PINMUX_DEFAULT for SERCOM pads + * + * Those default configuration only available if the device supports it: + * - High speed baudrate 3.4MHz + * - Standard-mode and Fast-mode transfer speed + * - SCL stretch disabled + * - Slave SCL low extend time-out disabled + * - Master SCL low extend time-out disabled + * + * \param[out] config Pointer to configuration structure to be initiated + */ +static inline void i2c_master_get_config_defaults( + struct i2c_master_config *const config) +{ + /*Sanity check argument */ + Assert(config); + config->baud_rate = I2C_MASTER_BAUD_RATE_100KHZ; +#ifdef FEATURE_I2C_FAST_MODE_PLUS_AND_HIGH_SPEED + config->baud_rate_high_speed = I2C_MASTER_BAUD_RATE_3400KHZ; + config->transfer_speed = I2C_MASTER_SPEED_STANDARD_AND_FAST; +#endif + config->generator_source = GCLK_GENERATOR_0; + config->run_in_standby = false; + config->start_hold_time = I2C_MASTER_START_HOLD_TIME_300NS_600NS; + config->buffer_timeout = 65535; + config->unknown_bus_state_timeout = 65535; + config->pinmux_pad0 = PINMUX_DEFAULT; + config->pinmux_pad1 = PINMUX_DEFAULT; + config->scl_low_timeout = false; + config->inactive_timeout = I2C_MASTER_INACTIVE_TIMEOUT_DISABLED; +#ifdef FEATURE_I2C_SCL_STRETCH_MODE + config->scl_stretch_only_after_ack_bit = false; +#endif +#ifdef FEATURE_I2C_SCL_EXTEND_TIMEOUT + config->slave_scl_low_extend_timeout = false; + config->master_scl_low_extend_timeout = false; +#endif + /* The typical value is 215ns */ + config->sda_scl_rise_time_ns = 215; +} + +enum status_code i2c_master_init( + struct i2c_master_module *const module, + Sercom *const hw, + const struct i2c_master_config *const config); + +/** + * \brief Enables the I2C module + * + * Enables the requested I2C module and set the bus state to IDLE + * after the specified \ref asfdoc_sam0_sercom_i2c_timeout "timeout" period if no + * stop bit is detected. + * + * \param[in] module Pointer to the software module struct + */ +static inline void i2c_master_enable( + const struct i2c_master_module *const module) +{ + /* Sanity check of arguments */ + Assert(module); + Assert(module->hw); + + SercomI2cm *const i2c_module = &(module->hw->I2CM); + + /* Timeout counter used to force bus state */ + uint32_t timeout_counter = 0; + + /* Wait for module to sync */ + _i2c_master_wait_for_sync(module); + + /* Enable module */ + i2c_module->CTRLA.reg |= SERCOM_I2CM_CTRLA_ENABLE; + +#if I2C_MASTER_CALLBACK_MODE == true + /* Enable module interrupts */ + system_interrupt_enable(_sercom_get_interrupt_vector(module->hw)); +#endif + /* Start timeout if bus state is unknown */ + while (!(i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_BUSSTATE(1))) { + timeout_counter++; + if(timeout_counter >= (module->unknown_bus_state_timeout)) { + /* Timeout, force bus state to idle */ + i2c_module->STATUS.reg = SERCOM_I2CM_STATUS_BUSSTATE(1); + /* Workaround #1 */ + return; + } + } +} + +/** + * \brief Disable the I2C module + * + * Disables the requested I2C module. + * + * \param[in] module Pointer to the software module struct + */ +static inline void i2c_master_disable( + const struct i2c_master_module *const module) +{ + /* Sanity check of arguments */ + Assert(module); + Assert(module->hw); + + SercomI2cm *const i2c_module = &(module->hw->I2CM); + +#if I2C_MASTER_CALLBACK_MODE == true + /* Disable module interrupts */ + system_interrupt_disable(_sercom_get_interrupt_vector(module->hw)); +#endif + + /* Wait for module to sync */ + _i2c_master_wait_for_sync(module); + + /* Disbale interrupt */ + i2c_module->INTENCLR.reg = SERCOM_I2CM_INTENCLR_MASK; + /* Clear interrupt flag */ + i2c_module->INTFLAG.reg = SERCOM_I2CM_INTFLAG_MASK; + + /* Disable module */ + i2c_module->CTRLA.reg &= ~SERCOM_I2CM_CTRLA_ENABLE; + +} + +void i2c_master_reset(struct i2c_master_module *const module); + +/** @} */ + +/** +* \name Read and Write +* @{ +*/ + +enum status_code i2c_master_read_packet_wait( + struct i2c_master_module *const module, + struct i2c_master_packet *const packet); + +enum status_code i2c_master_read_packet_wait_no_stop( + struct i2c_master_module *const module, + struct i2c_master_packet *const packet); + +enum status_code i2c_master_write_packet_wait( + struct i2c_master_module *const module, + struct i2c_master_packet *const packet); + +enum status_code i2c_master_write_packet_wait_no_stop( + struct i2c_master_module *const module, + struct i2c_master_packet *const packet); + +void i2c_master_send_stop(struct i2c_master_module *const module); + +void i2c_master_send_nack(struct i2c_master_module *const module); + +enum status_code i2c_master_read_byte( + struct i2c_master_module *const module, + uint8_t *byte); + +enum status_code i2c_master_write_byte( + struct i2c_master_module *const module, + uint8_t byte); + +enum status_code i2c_master_read_packet_wait_no_nack( + struct i2c_master_module *const module, + struct i2c_master_packet *const packet); + +/** @} */ + +#ifdef FEATURE_I2C_DMA_SUPPORT +/** +* \name SERCOM I2C Master with DMA Interfaces +* @{ +*/ + +/** + * \brief Set I2C for DMA transfer with slave address and transfer size. + * + * This function will set the slave address, transfer size and enable the auto transfer + * mode for DMA. + * + * \param[in,out] module Pointer to the driver instance to lock + * \param[in] addr I2C slave address + * \param[in] length I2C transfer length with DMA + * \param[in] direction I2C transfer direction + * + */ +static inline void i2c_master_dma_set_transfer(struct i2c_master_module *const module, + uint16_t addr, uint8_t length, enum i2c_transfer_direction direction) +{ + module->hw->I2CM.ADDR.reg = + SERCOM_I2CM_ADDR_ADDR(addr<<1) | + SERCOM_I2CM_ADDR_LENEN | + SERCOM_I2CM_ADDR_LEN(length) | + direction; +} + +/** @} */ +#endif + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* I2C_MASTER_H_INCLUDED */ diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/i2c/i2c_master_interrupt.h b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/i2c/i2c_master_interrupt.h new file mode 100644 index 000000000..34947ea85 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/i2c/i2c_master_interrupt.h @@ -0,0 +1,204 @@ +/** + * \file + * + * \brief SAM SERCOM I2C Master Interrupt Driver + * + * Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#ifndef I2C_MASTER_INTERRUPT_H_INCLUDED +#define I2C_MASTER_INTERRUPT_H_INCLUDED + +#include "i2c_master.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup asfdoc_sam0_sercom_i2c_group + * @{ + * + */ + +/** + * \name Callbacks + * @{ + */ +#if !defined(__DOXYGEN__) +void _i2c_master_interrupt_handler( + uint8_t instance); +#endif + +void i2c_master_register_callback( + struct i2c_master_module *const module, + i2c_master_callback_t callback, + enum i2c_master_callback callback_type); + +void i2c_master_unregister_callback( + struct i2c_master_module *const module, + enum i2c_master_callback callback_type); + +/** + * \brief Enables callback + * + * Enables the callback specified by the callback_type. + * + * \param[in,out] module Pointer to the software module struct + * \param[in] callback_type Callback type to enable + */ +static inline void i2c_master_enable_callback( + struct i2c_master_module *const module, + enum i2c_master_callback callback_type) +{ + /* Sanity check */ + Assert(module); + Assert(module->hw); + + /* Mark callback as enabled */ + module->enabled_callback |= (1 << callback_type); +} + +/** + * \brief Disables callback + * + * Disables the callback specified by the callback_type. + * + * \param[in,out] module Pointer to the software module struct + * \param[in] callback_type Callback type to disable + */ +static inline void i2c_master_disable_callback( + struct i2c_master_module *const module, + enum i2c_master_callback callback_type) +{ + /* Sanity check */ + Assert(module); + Assert(module->hw); + + /* Mark callback as disabled */ + module->enabled_callback &= ~(1 << callback_type); +} + +/** @} */ + +/** + * \name Read and Write, Interrupt-driven + * @{ + */ + +enum status_code i2c_master_read_bytes( + struct i2c_master_module *const module, + struct i2c_master_packet *const packet); + +enum status_code i2c_master_read_packet_job( + struct i2c_master_module *const module, + struct i2c_master_packet *const packet); + +enum status_code i2c_master_read_packet_job_no_stop( + struct i2c_master_module *const module, + struct i2c_master_packet *const packet); + +enum status_code i2c_master_read_packet_job_no_nack( + struct i2c_master_module *const module, + struct i2c_master_packet *const packet); + +enum status_code i2c_master_write_bytes( + struct i2c_master_module *const module, + struct i2c_master_packet *const packet); + +enum status_code i2c_master_write_packet_job( + struct i2c_master_module *const module, + struct i2c_master_packet *const packet); + +enum status_code i2c_master_write_packet_job_no_stop( + struct i2c_master_module *const module, + struct i2c_master_packet *const packet); + +/** + * \brief Cancel any currently ongoing operation + * + * Terminates the running transfer operation. + * + * \param[in,out] module Pointer to software module structure + */ +static inline void i2c_master_cancel_job( + struct i2c_master_module *const module) +{ + /* Sanity check */ + Assert(module); + Assert(module->hw); + + /* Set buffer to 0 */ + module->buffer_remaining = 0; + /* Update status */ + module->status = STATUS_ABORTED; +} + +/** + * \brief Get status from ongoing job + * + * Will return the status of a transfer operation. + * + * \param[in] module Pointer to software module structure + * + * \return Last status code from transfer operation. + * \retval STATUS_OK No error has occurred + * \retval STATUS_BUSY If transfer is in progress + * \retval STATUS_BUSY If master module is busy + * \retval STATUS_ERR_DENIED If error on bus + * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost + * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave + * acknowledged the address + * \retval STATUS_ERR_TIMEOUT If timeout occurred + * \retval STATUS_ERR_OVERFLOW If slave did not acknowledge last sent + * data, indicating that slave does not + * want more data and was not able to read + */ +static inline enum status_code i2c_master_get_job_status( + struct i2c_master_module *const module) +{ + /* Check sanity */ + Assert(module); + Assert(module->hw); + + /* Return current status code */ + return module->status; +} + +/** @} */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* I2C_MASTER_INTERRUPT_H_INCLUDED */ diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/i2c/i2c_sam0/i2c_master.c b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/i2c/i2c_sam0/i2c_master.c new file mode 100644 index 000000000..e8ce735c1 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/i2c/i2c_sam0/i2c_master.c @@ -0,0 +1,1040 @@ +/** + * \file + * + * \brief SAM I2C Master Driver + * + * Copyright (c) 2012-2020 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#include "i2c_master.h" + +#if I2C_MASTER_CALLBACK_MODE == true +# include "i2c_master_interrupt.h" +#endif + +/* Forward declaration */ +enum status_code _i2c_master_wait_for_bus( + struct i2c_master_module *const module); + +enum status_code _i2c_master_address_response( + struct i2c_master_module *const module); + +enum status_code _i2c_master_send_hs_master_code( + struct i2c_master_module *const module, + uint8_t hs_master_code); + +#if !defined(__DOXYGEN__) + +/** + * \internal Sets configurations to module + * + * \param[out] module Pointer to software module structure + * \param[in] config Configuration structure with configurations to set + * + * \return Status of setting configuration. + * \retval STATUS_OK If module was configured correctly + * \retval STATUS_ERR_ALREADY_INITIALIZED If setting other GCLK generator than + * previously set + * \retval STATUS_ERR_BAUDRATE_UNAVAILABLE If given baudrate is not compatible + * with set GCLK frequency + */ +static enum status_code _i2c_master_set_config( + struct i2c_master_module *const module, + const struct i2c_master_config *const config) +{ + /* Sanity check arguments. */ + Assert(module); + Assert(module->hw); + Assert(config); + + /* Temporary variables. */ + uint32_t tmp_ctrla; + int32_t tmp_baud = 0; + int32_t tmp_baud_hs = 0; + int32_t tmp_baudlow_hs = 0; + enum status_code tmp_status_code = STATUS_OK; + + SercomI2cm *const i2c_module = &(module->hw->I2CM); + Sercom *const sercom_hw = module->hw; + + uint8_t sercom_index = _sercom_get_sercom_inst_index(sercom_hw); + + /* Pin configuration */ + struct system_pinmux_config pin_conf; + system_pinmux_get_config_defaults(&pin_conf); + + uint32_t pad0 = config->pinmux_pad0; + uint32_t pad1 = config->pinmux_pad1; + + /* SERCOM PAD0 - SDA */ + if (pad0 == PINMUX_DEFAULT) { + pad0 = _sercom_get_default_pad(sercom_hw, 0); + } + pin_conf.mux_position = pad0 & 0xFFFF; + pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK; + system_pinmux_pin_set_config(pad0 >> 16, &pin_conf); + + /* SERCOM PAD1 - SCL */ + if (pad1 == PINMUX_DEFAULT) { + pad1 = _sercom_get_default_pad(sercom_hw, 1); + } + pin_conf.mux_position = pad1 & 0xFFFF; + pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK; + system_pinmux_pin_set_config(pad1 >> 16, &pin_conf); + + /* Save timeout on unknown bus state in software module. */ + module->unknown_bus_state_timeout = config->unknown_bus_state_timeout; + + /* Save timeout on buffer write. */ + module->buffer_timeout = config->buffer_timeout; + + /* Set whether module should run in standby. */ + if (config->run_in_standby || system_is_debugger_present()) { + tmp_ctrla = SERCOM_I2CM_CTRLA_RUNSTDBY; + } else { + tmp_ctrla = 0; + } + + /* Check and set start data hold timeout. */ + if (config->start_hold_time != I2C_MASTER_START_HOLD_TIME_DISABLED) { + tmp_ctrla |= config->start_hold_time; + } + + /* Check and set transfer speed */ + tmp_ctrla |= config->transfer_speed; + + /* Check and set SCL low timeout. */ + if (config->scl_low_timeout) { + tmp_ctrla |= SERCOM_I2CM_CTRLA_LOWTOUTEN; + } + + /* Check and set inactive bus timeout. */ + if (config->inactive_timeout != I2C_MASTER_INACTIVE_TIMEOUT_DISABLED) { + tmp_ctrla |= config->inactive_timeout; + } + + /* Check and set SCL clock stretch mode. */ + if (config->scl_stretch_only_after_ack_bit || (config->transfer_speed == I2C_MASTER_SPEED_HIGH_SPEED)) { + tmp_ctrla |= SERCOM_I2CM_CTRLA_SCLSM; + } + + /* Check and set slave SCL low extend timeout. */ + if (config->slave_scl_low_extend_timeout) { + tmp_ctrla |= SERCOM_I2CM_CTRLA_SEXTTOEN; + } + + /* Check and set master SCL low extend timeout. */ + if (config->master_scl_low_extend_timeout) { + tmp_ctrla |= SERCOM_I2CM_CTRLA_MEXTTOEN; + } + + /* Write config to register CTRLA. */ + i2c_module->CTRLA.reg |= tmp_ctrla; + + /* Set configurations in CTRLB. */ + i2c_module->CTRLB.reg = SERCOM_I2CM_CTRLB_SMEN; + + /* Find and set baudrate, considering sda/scl rise time */ + uint32_t fgclk = system_gclk_chan_get_hz(SERCOM0_GCLK_ID_CORE + sercom_index); + uint32_t fscl = 1000 * config->baud_rate; + uint32_t fscl_hs = 1000 * config->baud_rate_high_speed; + uint32_t trise = config->sda_scl_rise_time_ns; + + tmp_baud = (int32_t)(div_ceil( + fgclk - fscl * (10 + (fgclk * 0.000000001)* trise), 2 * fscl)); + + /* For High speed mode, set the SCL ratio of high:low to 1:2. */ + if (config->transfer_speed == I2C_MASTER_SPEED_HIGH_SPEED) { + tmp_baudlow_hs = (int32_t)((fgclk * 2.0) / (3.0 * fscl_hs) - 1); + if (tmp_baudlow_hs) { + tmp_baud_hs = (int32_t)(fgclk / fscl_hs) - 2 - tmp_baudlow_hs; + } else { + tmp_baud_hs = (int32_t)(div_ceil(fgclk, 2 * fscl_hs)) - 1; + } + } + + /* Check that baudrate is supported at current speed. */ + if (tmp_baud > 255 || tmp_baud < 0 || tmp_baud_hs > 255 || tmp_baud_hs < 0) { + /* Baud rate not supported. */ + tmp_status_code = STATUS_ERR_BAUDRATE_UNAVAILABLE; + } + if (tmp_status_code != STATUS_ERR_BAUDRATE_UNAVAILABLE) { + /* Baud rate acceptable. */ + i2c_module->BAUD.reg = SERCOM_I2CM_BAUD_BAUD(tmp_baud) | + SERCOM_I2CM_BAUD_HSBAUD(tmp_baud_hs) | SERCOM_I2CM_BAUD_HSBAUDLOW(tmp_baudlow_hs); + } + + return tmp_status_code; +} +#endif /* __DOXYGEN__ */ + +/** + * \brief Initializes the requested I2C hardware module + * + * Initializes the SERCOM I2C master device requested and sets the provided + * software module struct. Run this function before any further use of + * the driver. + * + * \param[out] module Pointer to software module struct + * \param[in] hw Pointer to the hardware instance + * \param[in] config Pointer to the configuration struct + * + * \return Status of initialization. + * \retval STATUS_OK Module initiated correctly + * \retval STATUS_ERR_DENIED If module is enabled + * \retval STATUS_BUSY If module is busy resetting + * \retval STATUS_ERR_ALREADY_INITIALIZED If setting other GCLK generator than + * previously set + * \retval STATUS_ERR_BAUDRATE_UNAVAILABLE If given baudrate is not compatible + * with set GCLK frequency + * + */ +enum status_code i2c_master_init( + struct i2c_master_module *const module, + Sercom *const hw, + const struct i2c_master_config *const config) +{ + /* Sanity check arguments. */ + Assert(module); + Assert(hw); + Assert(config); + + /* Initialize software module */ + module->hw = hw; + + SercomI2cm *const i2c_module = &(module->hw->I2CM); + + uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw); + uint32_t pm_index, gclk_index; + +#if (SAML22) || (SAMC20) + pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos; + gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; +#elif (SAML21) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + if (sercom_index == 5) { + pm_index = MCLK_APBDMASK_SERCOM5_Pos; + gclk_index = SERCOM5_GCLK_ID_CORE; + } else { + pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos; + gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; + } +#elif (SAMC21) + pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos; + if (sercom_index == 5) { + gclk_index = SERCOM5_GCLK_ID_CORE; + } else { + gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; + } +#else + pm_index = sercom_index + PM_APBCMASK_SERCOM0_Pos; + gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; +#endif + + /* Turn on module in PM */ +#if (SAML21) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + if (sercom_index == 5) { + system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBD, 1 << pm_index); + } else { + system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index); + } +#else + system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index); +#endif + + /* Set up the GCLK for the module */ + struct system_gclk_chan_config gclk_chan_conf; + system_gclk_chan_get_config_defaults(&gclk_chan_conf); + gclk_chan_conf.source_generator = config->generator_source; + system_gclk_chan_set_config(gclk_index, &gclk_chan_conf); + system_gclk_chan_enable(gclk_index); + sercom_set_gclk_generator(config->generator_source, false); + + /* Check if module is enabled. */ + if (i2c_module->CTRLA.reg & SERCOM_I2CM_CTRLA_ENABLE) { + return STATUS_ERR_DENIED; + } + + /* Check if reset is in progress. */ + if (i2c_module->CTRLA.reg & SERCOM_I2CM_CTRLA_SWRST) { + return STATUS_BUSY; + } + +#if I2C_MASTER_CALLBACK_MODE == true + /* Get sercom instance index and register callback. */ + uint8_t instance_index = _sercom_get_sercom_inst_index(module->hw); + _sercom_set_handler(instance_index, _i2c_master_interrupt_handler); + _sercom_instances[instance_index] = module; + + /* Initialize values in module. */ + module->registered_callback = 0; + module->enabled_callback = 0; + module->buffer_length = 0; + module->buffer_remaining = 0; + + module->status = STATUS_OK; + module->buffer = NULL; +#endif + + /* Set sercom module to operate in I2C master mode. */ + i2c_module->CTRLA.reg = SERCOM_I2CM_CTRLA_MODE(0x5); + + /* Set config and return status. */ + return _i2c_master_set_config(module, config); +} + +/** + * \brief Resets the hardware module + * + * Reset the module to hardware defaults. + * + * \param[in,out] module Pointer to software module structure + */ +void i2c_master_reset(struct i2c_master_module *const module) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + SercomI2cm *const i2c_module = &(module->hw->I2CM); + + /* Wait for sync */ + _i2c_master_wait_for_sync(module); + + /* Disable module */ + i2c_master_disable(module); + +#if I2C_MASTER_CALLBACK_MODE == true + /* Clear all pending interrupts */ + system_interrupt_enter_critical_section(); + system_interrupt_clear_pending(_sercom_get_interrupt_vector(module->hw)); + system_interrupt_leave_critical_section(); +#endif + + /* Wait for sync */ + _i2c_master_wait_for_sync(module); + + /* Reset module */ + i2c_module->CTRLA.reg = SERCOM_I2CM_CTRLA_SWRST; +} + +#if !defined(__DOXYGEN__) +/** + * \internal + * Address response. Called when address is answered or timed out. + * + * \param[in,out] module Pointer to software module structure + * + * \return Status of address response. + * \retval STATUS_OK No error has occurred + * \retval STATUS_ERR_DENIED If error on bus + * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost + * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave + * acknowledged the address + */ +enum status_code _i2c_master_address_response( + struct i2c_master_module *const module) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + SercomI2cm *const i2c_module = &(module->hw->I2CM); + + /* Check for error and ignore bus-error; workaround for BUSSTATE stuck in + * BUSY */ + if (i2c_module->INTFLAG.reg & SERCOM_I2CM_INTFLAG_SB) { + + /* Clear write interrupt flag */ + i2c_module->INTFLAG.reg = SERCOM_I2CM_INTFLAG_SB; + + /* Check arbitration. */ + if (i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_ARBLOST) { + /* Return packet collision. */ + return STATUS_ERR_PACKET_COLLISION; + } + /* Check that slave responded with ack. */ + } else if (i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_RXNACK) { + /* Slave busy. Issue ack and stop command. */ + i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3); + + /* Return bad address value. */ + return STATUS_ERR_BAD_ADDRESS; + } + + return STATUS_OK; +} + +/** + * \internal + * Waits for answer on bus. + * + * \param[in,out] module Pointer to software module structure + * + * \return Status of bus. + * \retval STATUS_OK If given response from slave device + * \retval STATUS_ERR_TIMEOUT If no response was given within specified timeout + * period + */ +enum status_code _i2c_master_wait_for_bus( + struct i2c_master_module *const module) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + SercomI2cm *const i2c_module = &(module->hw->I2CM); + + /* Wait for reply. */ + uint16_t timeout_counter = 0; + while (!(i2c_module->INTFLAG.reg & SERCOM_I2CM_INTFLAG_MB) && + !(i2c_module->INTFLAG.reg & SERCOM_I2CM_INTFLAG_SB)) { + + /* Check timeout condition. */ + if (++timeout_counter >= module->buffer_timeout) { + return STATUS_ERR_TIMEOUT; + } + } + return STATUS_OK; +} +#endif /* __DOXYGEN__ */ + +/** + * \internal + * Send master code for high speed transfer. + * + * \param[in,out] module Pointer to software module structure + * \param[in] hs_master_code 8-bit master code (0000 1XXX) + * + * \return Status of bus. + * \retval STATUS_OK No error happen + */ +enum status_code _i2c_master_send_hs_master_code( + struct i2c_master_module *const module, + uint8_t hs_master_code) +{ + SercomI2cm *const i2c_module = &(module->hw->I2CM); + /* Return value. */ + enum status_code tmp_status; + + /* Set NACK for high speed code */ + i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT; + /* Send high speed code */ + i2c_module->ADDR.reg = hs_master_code; + /* Wait for response on bus. */ + tmp_status = _i2c_master_wait_for_bus(module); + /* Clear write interrupt flag */ + i2c_module->INTFLAG.reg = SERCOM_I2CM_INTENCLR_MB; + + return tmp_status; +} + + +/** + * \internal + * Starts blocking read operation. + * + * \param[in,out] module Pointer to software module struct + * \param[in,out] packet Pointer to I2C packet to transfer + * + * \return Status of reading packet. + * \retval STATUS_OK The packet was read successfully + * \retval STATUS_ERR_TIMEOUT If no response was given within + * specified timeout period + * \retval STATUS_ERR_DENIED If error on bus + * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost + * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave + * acknowledged the address + * + */ +static enum status_code _i2c_master_read_packet( + struct i2c_master_module *const module, + struct i2c_master_packet *const packet) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + Assert(packet); + + SercomI2cm *const i2c_module = &(module->hw->I2CM); + + /* Return value. */ + enum status_code tmp_status; + uint16_t tmp_data_length = packet->data_length; + + /* Written buffer counter. */ + uint16_t counter = 0; + + bool sclsm_flag = i2c_module->CTRLA.bit.SCLSM; + + /* Switch to high speed mode */ + if (packet->high_speed) { + _i2c_master_send_hs_master_code(module, packet->hs_master_code); + } + + /* Set action to ACK. */ + i2c_module->CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT; + + /* Set address and direction bit. Will send start command on bus. */ + if (packet->ten_bit_address) { + /* + * Write ADDR.ADDR[10:1] with the 10-bit address. ADDR.TENBITEN must + * be set and read/write bit (ADDR.ADDR[0]) equal to 0. + */ + i2c_module->ADDR.reg = (packet->address << 1) | + (packet->high_speed << SERCOM_I2CM_ADDR_HS_Pos) | + SERCOM_I2CM_ADDR_TENBITEN; + + /* Wait for response on bus. */ + tmp_status = _i2c_master_wait_for_bus(module); + + /* Set action to ack. */ + i2c_module->CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT; + + /* Check for address response error unless previous error is + * detected. */ + if (tmp_status == STATUS_OK) { + tmp_status = _i2c_master_address_response(module); + } + + if (tmp_status == STATUS_OK) { + /* + * Write ADDR[7:0] register to "11110 address[9:8] 1" + * ADDR.TENBITEN must be cleared + */ + i2c_module->ADDR.reg = (((packet->address >> 8) | 0x78) << 1) | + (packet->high_speed << SERCOM_I2CM_ADDR_HS_Pos) | + I2C_TRANSFER_READ; + } else { + return tmp_status; + } + } else { + i2c_module->ADDR.reg = (packet->address << 1) | I2C_TRANSFER_READ | + (packet->high_speed << SERCOM_I2CM_ADDR_HS_Pos); + } + + /* Wait for response on bus. */ + tmp_status = _i2c_master_wait_for_bus(module); + + /* Set action to ack or nack. */ + if ((sclsm_flag) && (packet->data_length == 1)) { + i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT; + } else { + i2c_module->CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT; + } + + /* Check for address response error unless previous error is + * detected. */ + if (tmp_status == STATUS_OK) { + tmp_status = _i2c_master_address_response(module); + } + + /* Check that no error has occurred. */ + if (tmp_status == STATUS_OK) { + /* Read data buffer. */ + while (tmp_data_length--) { + /* Check that bus ownership is not lost. */ + if (!(i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_BUSSTATE(2))) { + return STATUS_ERR_PACKET_COLLISION; + } + + if (module->send_nack && (((!sclsm_flag) && (tmp_data_length == 0)) || + ((sclsm_flag) && (tmp_data_length == 1)))) { + /* Set action to NACK */ + i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT; + } else { + /* Save data to buffer. */ + _i2c_master_wait_for_sync(module); + packet->data[counter++] = i2c_module->DATA.reg; + /* Wait for response. */ + tmp_status = _i2c_master_wait_for_bus(module); + } + + /* Check for error. */ + if (tmp_status != STATUS_OK) { + break; + } + } + + if (module->send_stop) { + /* Send stop command unless arbitration is lost. */ + _i2c_master_wait_for_sync(module); + i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3); + } + + /* Save last data to buffer. */ + _i2c_master_wait_for_sync(module); + packet->data[counter] = i2c_module->DATA.reg; + } + + return tmp_status; +} + +/** + * \brief Reads data packet from slave + * + * Reads a data packet from the specified slave address on the I2C + * bus and sends a stop condition when finished. + * + * \note This will stall the device from any other operation. For + * interrupt-driven operation, see \ref i2c_master_read_packet_job. + * + * \param[in,out] module Pointer to software module struct + * \param[in,out] packet Pointer to I2C packet to transfer + * + * \return Status of reading packet. + * \retval STATUS_OK The packet was read successfully + * \retval STATUS_ERR_TIMEOUT If no response was given within + * specified timeout period + * \retval STATUS_ERR_DENIED If error on bus + * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost + * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave + * acknowledged the address + */ +enum status_code i2c_master_read_packet_wait( + struct i2c_master_module *const module, + struct i2c_master_packet *const packet) +{ + /* Sanity check */ + Assert(module); + Assert(module->hw); + Assert(packet); + +#if I2C_MASTER_CALLBACK_MODE == true + /* Check if the I2C module is busy with a job. */ + if (module->buffer_remaining > 0) { + return STATUS_BUSY; + } +#endif + + module->send_stop = true; + module->send_nack = true; + + return _i2c_master_read_packet(module, packet); +} + +/** + * \brief Reads data packet from slave without sending a stop condition when done + * + * Reads a data packet from the specified slave address on the I2C + * bus without sending a stop condition when done, thus retaining ownership of + * the bus when done. To end the transaction, a + * \ref i2c_master_read_packet_wait "read" or + * \ref i2c_master_write_packet_wait "write" with stop condition must be + * performed. + * + * \note This will stall the device from any other operation. For + * interrupt-driven operation, see \ref i2c_master_read_packet_job. + * + * \param[in,out] module Pointer to software module struct + * \param[in,out] packet Pointer to I2C packet to transfer + * + * \return Status of reading packet. + * \retval STATUS_OK The packet was read successfully + * \retval STATUS_ERR_TIMEOUT If no response was given within + * specified timeout period + * \retval STATUS_ERR_DENIED If error on bus + * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost + * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave + * acknowledged the address + */ +enum status_code i2c_master_read_packet_wait_no_stop( + struct i2c_master_module *const module, + struct i2c_master_packet *const packet) +{ + /* Sanity check */ + Assert(module); + Assert(module->hw); + Assert(packet); + +#if I2C_MASTER_CALLBACK_MODE == true + /* Check if the I2C module is busy with a job. */ + if (module->buffer_remaining > 0) { + return STATUS_BUSY; + } +#endif + + module->send_stop = false; + module->send_nack = true; + + return _i2c_master_read_packet(module, packet); +} + +/** + * \internal + * Starts blocking read operation. + * \brief Reads data packet from slave without sending a nack signal and a stop + * condition when done + * + * Reads a data packet from the specified slave address on the I2C + * bus without sending a nack signal and a stop condition when done, + * thus retaining ownership of the bus when done. To end the transaction, a + * \ref i2c_master_read_packet_wait "read" or + * \ref i2c_master_write_packet_wait "write" with stop condition must be + * performed. + * + * \note This will stall the device from any other operation. For + * interrupt-driven operation, see \ref i2c_master_read_packet_job. + * + * \param[in,out] module Pointer to software module struct + * \param[in,out] packet Pointer to I2C packet to transfer + * + * \return Status of reading packet. + * \retval STATUS_OK The packet was read successfully + * \retval STATUS_ERR_TIMEOUT If no response was given within + * specified timeout period + * \retval STATUS_ERR_DENIED If error on bus + * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost + * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave + * acknowledged the address + */ +enum status_code i2c_master_read_packet_wait_no_nack( + struct i2c_master_module *const module, + struct i2c_master_packet *const packet) +{ + /* Sanity check */ + Assert(module); + Assert(module->hw); + Assert(packet); + +#if I2C_MASTER_CALLBACK_MODE == true + /* Check if the I2C module is busy with a job. */ + if (module->buffer_remaining > 0) { + return STATUS_BUSY; + } +#endif + + module->send_stop = false; + module->send_nack = false; + + return _i2c_master_read_packet(module, packet); +} + +/** + * \internal + * Starts blocking write operation. + * + * \param[in,out] module Pointer to software module struct + * \param[in,out] packet Pointer to I2C packet to transfer + * + * \return Status of write packet. + * \retval STATUS_OK The packet was write successfully + * \retval STATUS_ERR_TIMEOUT If no response was given within + * specified timeout period + * \retval STATUS_ERR_DENIED If error on bus + * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost + * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave + * acknowledged the address + */ +static enum status_code _i2c_master_write_packet( + struct i2c_master_module *const module, + struct i2c_master_packet *const packet) +{ + SercomI2cm *const i2c_module = &(module->hw->I2CM); + + /* Return value. */ + enum status_code tmp_status; + uint16_t tmp_data_length = packet->data_length; + + _i2c_master_wait_for_sync(module); + + /* Switch to high speed mode */ + if (packet->high_speed) { + _i2c_master_send_hs_master_code(module, packet->hs_master_code); + } + + /* Set action to ACK. */ + i2c_module->CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT; + + /* Set address and direction bit. Will send start command on bus. */ + if (packet->ten_bit_address) { + i2c_module->ADDR.reg = (packet->address << 1) | I2C_TRANSFER_WRITE | + (packet->high_speed << SERCOM_I2CM_ADDR_HS_Pos) | + SERCOM_I2CM_ADDR_TENBITEN; + } else { + i2c_module->ADDR.reg = (packet->address << 1) | I2C_TRANSFER_WRITE | + (packet->high_speed << SERCOM_I2CM_ADDR_HS_Pos); + } + /* Wait for response on bus. */ + tmp_status = _i2c_master_wait_for_bus(module); + + /* Check for address response error unless previous error is + * detected. */ + if (tmp_status == STATUS_OK) { + tmp_status = _i2c_master_address_response(module); + } + + /* Check that no error has occurred. */ + if (tmp_status == STATUS_OK) { + /* Buffer counter. */ + uint16_t buffer_counter = 0; + + /* Write data buffer. */ + while (tmp_data_length--) { + /* Check that bus ownership is not lost. */ + if (!(i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_BUSSTATE(2))) { + return STATUS_ERR_PACKET_COLLISION; + } + + /* Write byte to slave. */ + _i2c_master_wait_for_sync(module); + i2c_module->DATA.reg = packet->data[buffer_counter++]; + + /* Wait for response. */ + tmp_status = _i2c_master_wait_for_bus(module); + + /* Check for error. */ + if (tmp_status != STATUS_OK) { + break; + } + + /* Check for NACK from slave. */ + if (i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_RXNACK) { + /* Return bad data value. */ + tmp_status = STATUS_ERR_OVERFLOW; + break; + } + } + + if (module->send_stop) { + /* Stop command */ + _i2c_master_wait_for_sync(module); + i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3); + } + } + + return tmp_status; +} + +/** + * \brief Writes data packet to slave + * + * Writes a data packet to the specified slave address on the I2C bus + * and sends a stop condition when finished. + * + * \note This will stall the device from any other operation. For + * interrupt-driven operation, see \ref i2c_master_read_packet_job. + * + * \param[in,out] module Pointer to software module struct + * \param[in,out] packet Pointer to I2C packet to transfer + * + * \return Status of write packet. + * \retval STATUS_OK If packet was write successfully + * \retval STATUS_BUSY If master module is busy with a job + * \retval STATUS_ERR_DENIED If error on bus + * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost + * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave + * acknowledged the address + * \retval STATUS_ERR_TIMEOUT If timeout occurred + * \retval STATUS_ERR_OVERFLOW If slave did not acknowledge last sent + * data, indicating that slave does not + * want more data and was not able to read + * last data sent + */ +enum status_code i2c_master_write_packet_wait( + struct i2c_master_module *const module, + struct i2c_master_packet *const packet) +{ + /* Sanity check */ + Assert(module); + Assert(module->hw); + Assert(packet); + +#if I2C_MASTER_CALLBACK_MODE == true + /* Check if the I2C module is busy with a job */ + if (module->buffer_remaining > 0) { + return STATUS_BUSY; + } +#endif + + module->send_stop = true; + module->send_nack = true; + + return _i2c_master_write_packet(module, packet); +} + +/** + * \brief Writes data packet to slave without sending a stop condition when done + * + * Writes a data packet to the specified slave address on the I2C bus + * without sending a stop condition, thus retaining ownership of the bus when + * done. To end the transaction, a \ref i2c_master_read_packet_wait "read" or + * \ref i2c_master_write_packet_wait "write" with stop condition or sending a + * stop with the \ref i2c_master_send_stop function must be performed. + * + * \note This will stall the device from any other operation. For + * interrupt-driven operation, see \ref i2c_master_read_packet_job. + * + * \param[in,out] module Pointer to software module struct + * \param[in,out] packet Pointer to I2C packet to transfer + * + * \return Status of write packet. + * \retval STATUS_OK If packet was write successfully + * \retval STATUS_BUSY If master module is busy + * \retval STATUS_ERR_DENIED If error on bus + * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost + * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave + * acknowledged the address + * \retval STATUS_ERR_TIMEOUT If timeout occurred + * \retval STATUS_ERR_OVERFLOW If slave did not acknowledge last sent + * data, indicating that slave do not want + * more data + */ +enum status_code i2c_master_write_packet_wait_no_stop( + struct i2c_master_module *const module, + struct i2c_master_packet *const packet) +{ + /* Sanity check */ + Assert(module); + Assert(module->hw); + Assert(packet); + +#if I2C_MASTER_CALLBACK_MODE == true + /* Check if the I2C module is busy with a job */ + if (module->buffer_remaining > 0) { + return STATUS_BUSY; + } +#endif + + module->send_stop = false; + module->send_nack = true; + + return _i2c_master_write_packet(module, packet); +} + +/** + * \brief Sends stop condition on bus + * + * Sends a stop condition on bus. + * + * \note This function can only be used after the + * \ref i2c_master_write_packet_wait_no_stop function. If a stop condition + * is to be sent after a read, the \ref i2c_master_read_packet_wait + * function must be used. + * + * \param[in,out] module Pointer to the software instance struct + */ +void i2c_master_send_stop(struct i2c_master_module *const module) +{ + /* Sanity check */ + Assert(module); + Assert(module->hw); + + SercomI2cm *const i2c_module = &(module->hw->I2CM); + + /* Send stop command */ + _i2c_master_wait_for_sync(module); + i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3); +} + +/** + * \brief Sends nack signal on bus + * + * Sends a nack signal on bus. + * + * \note This function can only be used after the + * \ref i2c_master_write_packet_wait_no_nack function, + * or \ref i2c_master_read_byte function. + * \param[in,out] module Pointer to the software instance struct + */ +void i2c_master_send_nack(struct i2c_master_module *const module) +{ + /* Sanity check */ + Assert(module); + Assert(module->hw); + + SercomI2cm *const i2c_module = &(module->hw->I2CM); + + /* Send nack signal */ + _i2c_master_wait_for_sync(module); + i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT; +} + +/** + * \brief Reads one byte data from slave + * + * \param[in,out] module Pointer to software module struct + * \param[out] byte Read one byte data to slave + * + * \return Status of reading byte. + * \retval STATUS_OK One byte was read successfully + * \retval STATUS_ERR_TIMEOUT If no response was given within + * specified timeout period + * \retval STATUS_ERR_DENIED If error on bus + * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost + * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave + * acknowledged the address + */ +enum status_code i2c_master_read_byte( + struct i2c_master_module *const module, + uint8_t *byte) +{ + enum status_code tmp_status; + SercomI2cm *const i2c_module = &(module->hw->I2CM); + + i2c_module->CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT; + /* Write byte to slave. */ + _i2c_master_wait_for_sync(module); + *byte = i2c_module->DATA.reg; + /* Wait for response. */ + tmp_status = _i2c_master_wait_for_bus(module); + + return tmp_status; +} + +/** + * \brief Write one byte data to slave + * + * \param[in,out] module Pointer to software module struct + * \param[in] byte Send one byte data to slave + * + * \return Status of writing byte. + * \retval STATUS_OK One byte was write successfully + * \retval STATUS_ERR_TIMEOUT If no response was given within + * specified timeout period + * \retval STATUS_ERR_DENIED If error on bus + * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost + * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave + * acknowledged the address + */ +enum status_code i2c_master_write_byte( + struct i2c_master_module *const module, + uint8_t byte) +{ + enum status_code tmp_status; + SercomI2cm *const i2c_module = &(module->hw->I2CM); + + /* Write byte to slave. */ + _i2c_master_wait_for_sync(module); + i2c_module->DATA.reg = byte; + /* Wait for response. */ + tmp_status = _i2c_master_wait_for_bus(module); + return tmp_status; +} diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/i2c/i2c_sam0/i2c_master_interrupt.c b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/i2c/i2c_sam0/i2c_master_interrupt.c new file mode 100644 index 000000000..66ae061d1 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/i2c/i2c_sam0/i2c_master_interrupt.c @@ -0,0 +1,752 @@ +/** + * \file + * + * \brief SAM I2C Master Interrupt Driver + * + * Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#include "i2c_master_interrupt.h" + +extern enum status_code _i2c_master_wait_for_bus( + struct i2c_master_module *const module); + +extern enum status_code _i2c_master_address_response( + struct i2c_master_module *const module); + +extern enum status_code _i2c_master_send_hs_master_code( + struct i2c_master_module *const module, + uint8_t hs_master_code);; + +/** + * \internal + * Read next data. Used by interrupt handler to get next data byte from slave. + * + * \param[in,out] module Pointer to software module structure + */ +static void _i2c_master_read( + struct i2c_master_module *const module) +{ + /* Sanity check arguments. */ + Assert(module); + Assert(module->hw); + + SercomI2cm *const i2c_module = &(module->hw->I2CM); + bool sclsm_flag = i2c_module->CTRLA.bit.SCLSM; + + /* Find index to save next value in buffer */ + uint16_t buffer_index = module->buffer_length; + buffer_index -= module->buffer_remaining; + + module->buffer_remaining--; + + if (sclsm_flag) { + if (module->send_nack && module->buffer_remaining == 1) { + /* Set action to NACK. */ + i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT; + } + } else { + if (module->send_nack && module->buffer_remaining == 0) { + /* Set action to NACK. */ + i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT; + } + } + + if (module->buffer_remaining == 0) { + if (module->send_stop) { + /* Send stop condition */ + _i2c_master_wait_for_sync(module); + i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3); + } + } + + /* Read byte from slave and put in buffer */ + _i2c_master_wait_for_sync(module); + module->buffer[buffer_index] = i2c_module->DATA.reg; +} + +/** + * \internal + * + * Write next data. Used by interrupt handler to send next data byte to slave. + * + * \param[in,out] module Pointer to software module structure + */ +static void _i2c_master_write(struct i2c_master_module *const module) +{ + /* Sanity check arguments. */ + Assert(module); + Assert(module->hw); + + SercomI2cm *const i2c_module = &(module->hw->I2CM); + + /* Check for ack from slave */ + if (i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_RXNACK) + { + /* Set status */ + module->status = STATUS_ERR_OVERFLOW; + /* Do not write more data */ + return; + } + + /* Find index to get next byte in buffer */ + uint16_t buffer_index = module->buffer_length; + buffer_index -= module->buffer_remaining; + + module->buffer_remaining--; + + /* Write byte from buffer to slave */ + _i2c_master_wait_for_sync(module); + i2c_module->DATA.reg = module->buffer[buffer_index]; +} + +/** + * \internal + * Acts on slave address response. Checks for errors concerning master->slave + * handshake. + * + * \param[in,out] module Pointer to software module structure + */ +static void _i2c_master_async_address_response( + struct i2c_master_module *const module) +{ + /* Sanity check arguments. */ + Assert(module); + Assert(module->hw); + + SercomI2cm *const i2c_module = &(module->hw->I2CM); + + /* Check for error. Ignore bus-error; workaround for bus state stuck in + * BUSY. + */ + if (i2c_module->INTFLAG.reg & SERCOM_I2CM_INTFLAG_MB) + { + /* Clear write interrupt flag */ + i2c_module->INTFLAG.reg = SERCOM_I2CM_INTENCLR_MB; + + /* Check arbitration */ + if (i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_ARBLOST) { + /* Return busy */ + module->status = STATUS_ERR_PACKET_COLLISION; + } + /* No slave responds */ + else if (i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_RXNACK) { + module->status = STATUS_ERR_BAD_ADDRESS; + module->buffer_remaining = 0; + + if (module->send_stop) { + /* Send stop condition */ + _i2c_master_wait_for_sync(module); + i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3); + } + } + } + + module->buffer_length = module->buffer_remaining; + + /* Check for status OK. */ + if (module->status == STATUS_BUSY) { + /* Call function based on transfer direction. */ + if (module->transfer_direction == I2C_TRANSFER_WRITE) { + _i2c_master_write(module); + } else { + _i2c_master_read(module); + } + } +} + +/** + * \brief Registers callback for the specified callback type + * + * Associates the given callback function with the + * specified callback type. + * + * To enable the callback, the \ref i2c_master_enable_callback function + * must be used. + * + * \param[in,out] module Pointer to the software module struct + * \param[in] callback Pointer to the function desired for the + * specified callback + * \param[in] callback_type Callback type to register + */ +void i2c_master_register_callback( + struct i2c_master_module *const module, + const i2c_master_callback_t callback, + enum i2c_master_callback callback_type) +{ + /* Sanity check */ + Assert(module); + Assert(module->hw); + Assert(callback); + + /* Register callback */ + module->callbacks[callback_type] = callback; + + /* Set corresponding bit to set callback as registered */ + module->registered_callback |= (1 << callback_type); +} + +/** + * \brief Unregisters callback for the specified callback type + * + * When called, the currently registered callback for the given callback type + * will be removed. + * + * \param[in,out] module Pointer to the software module struct + * \param[in] callback_type Specifies the callback type to unregister + */ +void i2c_master_unregister_callback( + struct i2c_master_module *const module, + enum i2c_master_callback callback_type) +{ + /* Sanity check */ + Assert(module); + Assert(module->hw); + + /* Register callback */ + module->callbacks[callback_type] = NULL; + + /* Clear corresponding bit to set callback as unregistered */ + module->registered_callback &= ~(1 << callback_type); +} + +/** + * \internal + * Starts a read bytes operation. + * + * \param[in,out] module Pointer to software module struct + * \param[in,out] packet Pointer to I2C packet to transfer + * + * \return Status of starting reading I2C packet. + * \retval STATUS_OK If reading was started successfully + * \retval STATUS_BUSY If module is currently busy with another transfer + */ +enum status_code i2c_master_read_bytes( + struct i2c_master_module *const module, + struct i2c_master_packet *const packet) +{ + /* Sanity check */ + Assert(module); + Assert(module->hw); + + SercomI2cm *const i2c_module = &(module->hw->I2CM); + + /* Save packet to software module */ + module->buffer = packet->data; + module->buffer_remaining = packet->data_length; + module->transfer_direction = I2C_TRANSFER_READ; + module->status = STATUS_BUSY; + module->send_stop = false; + module->send_nack = false; + + /* Enable interrupts */ + i2c_module->INTENSET.reg = + SERCOM_I2CM_INTENSET_MB | SERCOM_I2CM_INTENSET_SB; + + return STATUS_OK; +} + +/** + * \internal + * Starts a read packet operation. + * + * \param[in,out] module Pointer to software module struct + * \param[in,out] packet Pointer to I2C packet to transfer + * + * \return Status of starting reading I2C packet. + * \retval STATUS_OK If reading was started successfully + * \retval STATUS_BUSY If module is currently busy with another transfer + */ +static enum status_code _i2c_master_read_packet( + struct i2c_master_module *const module, + struct i2c_master_packet *const packet) +{ + /* Sanity check */ + Assert(module); + Assert(module->hw); + + SercomI2cm *const i2c_module = &(module->hw->I2CM); + enum status_code tmp_status; + + /* Save packet to software module */ + module->buffer = packet->data; + module->buffer_remaining = packet->data_length; + module->transfer_direction = I2C_TRANSFER_READ; + module->status = STATUS_BUSY; + + bool sclsm_flag = i2c_module->CTRLA.bit.SCLSM; + + /* Switch to high speed mode */ + if (packet->high_speed) { + _i2c_master_send_hs_master_code(module, packet->hs_master_code); + } + + /* Set action to ACK or NACK. */ + if ((sclsm_flag) && (packet->data_length == 1)) { + i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT; + } else { + i2c_module->CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT; + } + + if (packet->ten_bit_address) { + /* + * Write ADDR.ADDR[10:1] with the 10-bit address. ADDR.TENBITEN must + * be set and read/write bit (ADDR.ADDR[0]) equal to 0. + */ + i2c_module->ADDR.reg = (packet->address << 1) | + (packet->high_speed << SERCOM_I2CM_ADDR_HS_Pos) | + SERCOM_I2CM_ADDR_TENBITEN; + + /* Wait for response on bus. */ + tmp_status = _i2c_master_wait_for_bus(module); + + /* Set action to ack. */ + i2c_module->CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT; + + /* Check for address response error unless previous error is + * detected. */ + if (tmp_status == STATUS_OK) { + tmp_status = _i2c_master_address_response(module); + } + + if (tmp_status == STATUS_OK) { + /* Enable interrupts */ + i2c_module->INTENSET.reg = + SERCOM_I2CM_INTENSET_MB | SERCOM_I2CM_INTENSET_SB; + + /* + * Write ADDR[7:0] register to "11110 address[9:8] 1" + * ADDR.TENBITEN must be cleared + */ + i2c_module->ADDR.reg = (((packet->address >> 8) | 0x78) << 1) | + (packet->high_speed << SERCOM_I2CM_ADDR_HS_Pos) | + I2C_TRANSFER_READ; + } else { + return tmp_status; + } + } else { + /* Enable interrupts */ + i2c_module->INTENSET.reg = + SERCOM_I2CM_INTENSET_MB | SERCOM_I2CM_INTENSET_SB; + + /* Set address and direction bit. Will send start command on bus */ + i2c_module->ADDR.reg = (packet->address << 1) | I2C_TRANSFER_READ | + (packet->high_speed << SERCOM_I2CM_ADDR_HS_Pos); + } + + return STATUS_OK; +} + +/** + * \brief Initiates a read packet operation + * + * Reads a data packet from the specified slave address on the I2C + * bus. This is the non-blocking equivalent of \ref i2c_master_read_packet_wait. + * + * \param[in,out] module Pointer to software module struct + * \param[in,out] packet Pointer to I2C packet to transfer + * + * \return Status of starting reading I2C packet. + * \retval STATUS_OK If reading was started successfully + * \retval STATUS_BUSY If module is currently busy with another transfer + */ +enum status_code i2c_master_read_packet_job( + struct i2c_master_module *const module, + struct i2c_master_packet *const packet) +{ + /* Sanity check */ + Assert(module); + Assert(module->hw); + Assert(packet); + + /* Check if the I2C module is busy with a job */ + if (module->buffer_remaining > 0) { + return STATUS_BUSY; + } + + /* Make sure we send STOP */ + module->send_stop = true; + module->send_nack = true; + /* Start reading */ + return _i2c_master_read_packet(module, packet); +} + +/** + * \brief Initiates a read packet operation without sending a STOP condition when done + * + * Reads a data packet from the specified slave address on the I2C bus without + * sending a stop condition, thus retaining ownership of the bus when done. + * To end the transaction, a \ref i2c_master_read_packet_wait "read" or + * \ref i2c_master_write_packet_wait "write" with stop condition must be + * performed. + * + * This is the non-blocking equivalent of \ref i2c_master_read_packet_wait_no_stop. + * + * \param[in,out] module Pointer to software module struct + * \param[in,out] packet Pointer to I2C packet to transfer + * + * \return Status of starting reading I2C packet. + * \retval STATUS_OK If reading was started successfully + * \retval STATUS_BUSY If module is currently busy with another operation + */ +enum status_code i2c_master_read_packet_job_no_stop( + struct i2c_master_module *const module, + struct i2c_master_packet *const packet) +{ + /* Sanity check */ + Assert(module); + Assert(module->hw); + Assert(packet); + + /* Check if the I2C module is busy with a job */ + if (module->buffer_remaining > 0) { + return STATUS_BUSY; + } + + /* Make sure we don't send STOP */ + module->send_stop = false; + module->send_nack = true; + /* Start reading */ + return _i2c_master_read_packet(module, packet); +} + +/** + * \brief Initiates a read packet operation without sending a NACK signal and a + * STOP condition when done + * + * Reads a data packet from the specified slave address on the I2C bus without + * sending a nack and a stop condition, thus retaining ownership of the bus when done. + * To end the transaction, a \ref i2c_master_read_packet_wait "read" or + * \ref i2c_master_write_packet_wait "write" with stop condition must be + * performed. + * + * This is the non-blocking equivalent of \ref i2c_master_read_packet_wait_no_stop. + * + * \param[in,out] module Pointer to software module struct + * \param[in,out] packet Pointer to I2C packet to transfer + * + * \return Status of starting reading I2C packet. + * \retval STATUS_OK If reading was started successfully + * \retval STATUS_BUSY If module is currently busy with another operation + */ +enum status_code i2c_master_read_packet_job_no_nack( + struct i2c_master_module *const module, + struct i2c_master_packet *const packet) +{ + /* Sanity check */ + Assert(module); + Assert(module->hw); + Assert(packet); + + /* Check if the I2C module is busy with a job */ + if (module->buffer_remaining > 0) { + return STATUS_BUSY; + } + + /* Make sure we don't send STOP */ + module->send_stop = false; + module->send_nack = false; + /* Start reading */ + return _i2c_master_read_packet(module, packet); +} + +/** + * \internal + * Starts a write bytes operation. + * + * \param[in,out] module Pointer to software module struct + * \param[in,out] packet Pointer to I2C packet to transfer + * + * \return Status of starting write I2C bytes. + * \retval STATUS_OK If writing was started successfully + * \retval STATUS_BUSY If module is currently busy with another transfer + */ +enum status_code i2c_master_write_bytes( + struct i2c_master_module *const module, + struct i2c_master_packet *const packet) +{ + /* Sanity check */ + Assert(module); + Assert(module->hw); + + SercomI2cm *const i2c_module = &(module->hw->I2CM); + + /* Save packet to software module */ + module->buffer = packet->data; + module->buffer_remaining = packet->data_length; + module->transfer_direction = I2C_TRANSFER_WRITE; + module->status = STATUS_BUSY; + module->send_stop = false; + module->send_nack = false; + + /* Enable interrupts */ + i2c_module->INTENSET.reg = + SERCOM_I2CM_INTENSET_MB | SERCOM_I2CM_INTENSET_SB; + + return STATUS_OK; +} + +/** + * \internal Initiates a write packet operation + * + * \param[in,out] module Pointer to software module struct + * \param[in,out] packet Pointer to I2C packet to transfer + * + * \return Status of starting writing I2C packet job. + * \retval STATUS_OK If writing was started successfully + * \retval STATUS_BUSY If module is currently busy with another transfer + */ +static enum status_code _i2c_master_write_packet( + struct i2c_master_module *const module, + struct i2c_master_packet *const packet) +{ + /* Sanity check */ + Assert(module); + Assert(module->hw); + + SercomI2cm *const i2c_module = &(module->hw->I2CM); + + /* Switch to high speed mode */ + if (packet->high_speed) { + _i2c_master_send_hs_master_code(module, packet->hs_master_code); + } + + /* Set action to ACK. */ + i2c_module->CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT; + + /* Save packet to software module */ + module->buffer = packet->data; + module->buffer_remaining = packet->data_length; + module->transfer_direction = I2C_TRANSFER_WRITE; + module->status = STATUS_BUSY; + + /* Enable interrupts */ + i2c_module->INTENSET.reg = + SERCOM_I2CM_INTENSET_MB | SERCOM_I2CM_INTENSET_SB; + + /* Set address and direction bit, will send start command on bus */ + if (packet->ten_bit_address) { + i2c_module->ADDR.reg = (packet->address << 1) | I2C_TRANSFER_WRITE | + (packet->high_speed << SERCOM_I2CM_ADDR_HS_Pos) | + SERCOM_I2CM_ADDR_TENBITEN; + } else { + i2c_module->ADDR.reg = (packet->address << 1) | I2C_TRANSFER_WRITE | + (packet->high_speed << SERCOM_I2CM_ADDR_HS_Pos); + } + + return STATUS_OK; +} + +/** + * \brief Initiates a write packet operation + * + * Writes a data packet to the specified slave address on the I2C + * bus. This is the non-blocking equivalent of \ref i2c_master_write_packet_wait. + * + * \param[in,out] module Pointer to software module struct + * \param[in,out] packet Pointer to I2C packet to transfer + * + * \return Status of starting writing I2C packet job. + * \retval STATUS_OK If writing was started successfully + * \retval STATUS_BUSY If module is currently busy with another transfer + */ +enum status_code i2c_master_write_packet_job( + struct i2c_master_module *const module, + struct i2c_master_packet *const packet) +{ + /* Sanity check */ + Assert(module); + Assert(module->hw); + Assert(packet); + + /* Check if the I2C module is busy with another job. */ + if (module->buffer_remaining > 0) { + return STATUS_BUSY; + } + + /* Make sure we send STOP at end*/ + module->send_stop = true; + module->send_nack = true; + /* Start write operation */ + return _i2c_master_write_packet(module, packet); +} + +/** + * \brief Initiates a write packet operation without sending a STOP condition when done + * + * Writes a data packet to the specified slave address on the I2C bus + * without sending a stop condition, thus retaining ownership of the bus when + * done. To end the transaction, a \ref i2c_master_read_packet_wait "read" or + * \ref i2c_master_write_packet_wait "write" with stop condition or sending + * a stop with the \ref i2c_master_send_stop function must be performed. + * + * This is the non-blocking equivalent of \ref i2c_master_write_packet_wait_no_stop. + * + * \param[in,out] module Pointer to software module struct + * \param[in,out] packet Pointer to I2C packet to transfer + * + * \return Status of starting writing I2C packet job. + * \retval STATUS_OK If writing was started successfully + * \retval STATUS_BUSY If module is currently busy with another + */ +enum status_code i2c_master_write_packet_job_no_stop( + struct i2c_master_module *const module, + struct i2c_master_packet *const packet) +{ + /* Sanity check */ + Assert(module); + Assert(module->hw); + Assert(packet); + + /* Check if the I2C module is busy with another job. */ + if (module->buffer_remaining > 0) { + return STATUS_BUSY; + } + + /* Do not send stop condition when done */ + module->send_stop = false; + module->send_nack = true; + /* Start write operation */ + return _i2c_master_write_packet(module, packet); +} + +/** + * \internal + * Interrupt handler for I2C master. + * + * \param[in] instance SERCOM instance that triggered the interrupt + */ +void _i2c_master_interrupt_handler( + uint8_t instance) +{ + /* Get software module for callback handling */ + struct i2c_master_module *module = + (struct i2c_master_module*)_sercom_instances[instance]; + + Assert(module); + + SercomI2cm *const i2c_module = &(module->hw->I2CM); + bool sclsm_flag = i2c_module->CTRLA.bit.SCLSM; + + /* Combine callback registered and enabled masks */ + uint8_t callback_mask = module->enabled_callback; + callback_mask &= module->registered_callback; + + /* Check if the module should respond to address ack */ + if ((module->buffer_length <= 0) && (module->buffer_remaining > 0)) { + /* Call function for address response */ + _i2c_master_async_address_response(module); + + /* Check if buffer write is done */ + } else if ((module->buffer_length > 0) && (module->buffer_remaining <= 0) && + (module->status == STATUS_BUSY) && + (module->transfer_direction == I2C_TRANSFER_WRITE)) { + /* Stop packet operation */ + i2c_module->INTENCLR.reg = + SERCOM_I2CM_INTENCLR_MB | SERCOM_I2CM_INTENCLR_SB; + + module->buffer_length = 0; + module->status = STATUS_OK; + + if (module->send_stop) { + /* Send stop condition */ + _i2c_master_wait_for_sync(module); + i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3); + } else { + /* Clear write interrupt flag */ + i2c_module->INTFLAG.reg = SERCOM_I2CM_INTFLAG_MB; + } + + if (callback_mask & (1 << I2C_MASTER_CALLBACK_WRITE_COMPLETE)) { + module->callbacks[I2C_MASTER_CALLBACK_WRITE_COMPLETE](module); + } + + /* Continue buffer write/read */ + } else if ((module->buffer_length > 0) && (module->buffer_remaining > 0)){ + /* Check that bus ownership is not lost */ + if ((!(i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_BUSSTATE(2))) && + (!(sclsm_flag && (module->buffer_remaining == 1)))) { + module->status = STATUS_ERR_PACKET_COLLISION; + } else if (module->transfer_direction == I2C_TRANSFER_WRITE) { + _i2c_master_write(module); + } else { + _i2c_master_read(module); + } + } + + /* Check if read buffer transfer is complete */ + if ((module->buffer_length > 0) && (module->buffer_remaining <= 0) && + (module->status == STATUS_BUSY) && + (module->transfer_direction == I2C_TRANSFER_READ)) { + + /* Clear read interrupt flag */ + if (i2c_module->INTFLAG.reg & SERCOM_I2CM_INTFLAG_SB) { + i2c_module->INTFLAG.reg = SERCOM_I2CM_INTFLAG_SB; + } + /* Stop packet operation */ + i2c_module->INTENCLR.reg = + SERCOM_I2CM_INTENCLR_MB | SERCOM_I2CM_INTENCLR_SB; + module->buffer_length = 0; + module->status = STATUS_OK; + + /* Call appropriate callback if enabled and registered */ + if ((callback_mask & (1 << I2C_MASTER_CALLBACK_READ_COMPLETE)) + && (module->transfer_direction == I2C_TRANSFER_READ)) { + module->callbacks[I2C_MASTER_CALLBACK_READ_COMPLETE](module); + } else if ((callback_mask & (1 << I2C_MASTER_CALLBACK_WRITE_COMPLETE)) + && (module->transfer_direction == I2C_TRANSFER_WRITE)) { + module->callbacks[I2C_MASTER_CALLBACK_WRITE_COMPLETE](module); + } + } + + /* Check for error */ + if ((module->status != STATUS_BUSY) && (module->status != STATUS_OK)) { + /* Stop packet operation */ + i2c_module->INTENCLR.reg = SERCOM_I2CM_INTENCLR_MB | + SERCOM_I2CM_INTENCLR_SB; + + module->buffer_length = 0; + module->buffer_remaining = 0; + + /* Send nack and stop command unless arbitration is lost */ + if ((module->status != STATUS_ERR_PACKET_COLLISION) && + module->send_stop) { + _i2c_master_wait_for_sync(module); + i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT | + SERCOM_I2CM_CTRLB_CMD(3); + } + + /* Call error callback if enabled and registered */ + if (callback_mask & (1 << I2C_MASTER_CALLBACK_ERROR)) { + module->callbacks[I2C_MASTER_CALLBACK_ERROR](module); + } + } +} diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/i2c/quick_start_master/qs_i2c_master_basic_use.h b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/i2c/quick_start_master/qs_i2c_master_basic_use.h new file mode 100644 index 000000000..39b3f3c92 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/i2c/quick_start_master/qs_i2c_master_basic_use.h @@ -0,0 +1,108 @@ +/** + * \file + * + * \brief SAM SERCOM I2C Master Quick Start Guide + * + * Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ + +/** + * \page asfdoc_sam0_sercom_i2c_master_basic_use_case Quick Start Guide for SERCOM I2C Master - Basic + * + * In this use case, the I2C will used and set up as follows: + * - Master mode + * - 100KHz operation speed + * - Not operational in standby + * - 10000 packet timeout value + * - 65535 unknown bus state timeout value + * + * + * \section asfdoc_sam0_sercom_i2c_master_basic_use_case_prereq Prerequisites + * The device must be connected to an I2C slave. + * + * \section asfdoc_sam0_sercom_i2c_master_basic_use_setup Setup + * + * \subsection asfdoc_sam0_sercom_i2c_master_basic_use_setup_code Code + * The following must be added to the user application: + * + * - A sample buffer to send, a sample buffer to read: + * \snippet qs_i2c_master_basic_use.c packet_data + * + * - Slave address to access: + * \snippet qs_i2c_master_basic_use.c address + * + * - Number of times to try to send packet if it fails: + * \snippet qs_i2c_master_basic_use.c timeout + * + * - Globally accessible module structure: + * \snippet qs_i2c_master_basic_use.c dev_inst + * + * - Function for setting up the module: + * \snippet qs_i2c_master_basic_use.c initialize_i2c + * + * - Add to user application \c main(): + * \snippet qs_i2c_master_basic_use.c init + * + * \subsection asfdoc_sam0_sercom_i2c_master_basic_use_setup_workflow Workflow + * -# Configure and enable module. + * \snippet qs_i2c_master_basic_use.c initialize_i2c + * -# Create and initialize configuration structure. + * \snippet qs_i2c_master_basic_use.c init_conf + * -# Change settings in the configuration. + * \snippet qs_i2c_master_basic_use.c conf_change + * -# Initialize the module with the set configurations. + * \snippet qs_i2c_master_basic_use.c init_module + * -# Enable the module. + * \snippet qs_i2c_master_basic_use.c enable_module + * -# Create a variable to see when we should stop trying to send packet. + * \snippet qs_i2c_master_basic_use.c timeout_counter + * -# Create a packet to send. + * \snippet qs_i2c_master_basic_use.c packet + * + * \section asfdoc_sam0_sercom_i2c_master_basic_use_implemenation Implementation + * \subsection asfdoc_sam0_sercom_i2c_master_basic_use_implemenation_code Code + * Add to user application \c main(): + * \snippet qs_i2c_master_basic_use.c main + * + * \subsection asfdoc_sam0_sercom_i2c_master_basic_use_implemenation_workflow Workflow + * -# Write packet to slave. + * \snippet qs_i2c_master_basic_use.c write_packet + * The module will try to send the packet TIMEOUT number of times or until it is + * successfully sent. + * -# Read packet from slave. + * \snippet qs_i2c_master_basic_use.c read_packet + * The module will try to read the packet TIMEOUT number of times or until it is + * successfully read. + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#include +#include + diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/i2c/quick_start_master_callback/qs_i2c_master_callback.h b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/i2c/quick_start_master_callback/qs_i2c_master_callback.h new file mode 100644 index 000000000..67204f910 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/i2c/quick_start_master_callback/qs_i2c_master_callback.h @@ -0,0 +1,123 @@ +/** + * \file + * + * \brief SAM SERCOM I2C Master Interface Driver + * + * Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ + +/** + * \page asfdoc_sam0_sercom_i2c_master_callback_use_case Quick Start Guide for SERCOM I2C Master - Callback + * + * In this use case, the I2C will used and set up as follows: + * - Master mode + * - 100KHz operation speed + * - Not operational in standby + * - 65535 unknown bus state timeout value + * + * \section asfdoc_sam0_sercom_i2c_master_callback_use_case_prereq Prerequisites + * The device must be connected to an I2C slave. + * + * \section asfdoc_sam0_sercom_i2c_master_callback_use_case_setup Setup + * + * \subsection asfdoc_sam0_sercom_i2c_master_callback_use_case_setup_code Code + * The following must be added to the user application: + * + * A sample buffer to write from, a reversed buffer to write from and length of + * buffers. + * \snippet qs_i2c_master_callback.c packet_data + * + * Address of slave: + * \snippet qs_i2c_master_callback.c address + * + * Globally accessible module structure: + * \snippet qs_i2c_master_callback.c dev_inst + * + * Globally accessible packet: + * \snippet qs_i2c_master_callback.c packet_glob + * + * Function for setting up module: + * \snippet qs_i2c_master_callback.c initialize_i2c + * + * Callback function for write complete: + * \snippet qs_i2c_master_callback.c callback_func + * + * Function for setting up the callback functionality of the driver: + * \snippet qs_i2c_master_callback.c setup_callback + * + * Add to user application \c main(): + * \snippet qs_i2c_master_callback.c run_initialize_i2c + * + * \subsection asfdoc_sam0_sercom_i2c_master_callback_use_case_setup_workflow Workflow + * -# Configure and enable module. + * \snippet qs_i2c_master_callback.c config + * -# Create and initialize configuration structure. + * \snippet qs_i2c_master_callback.c init_conf + * -# Change settings in the configuration. + * \snippet qs_i2c_master_callback.c conf_change + * -# Initialize the module with the set configurations. + * \snippet qs_i2c_master_callback.c init_module + * -# Enable the module. + * \snippet qs_i2c_master_callback.c enable_module + * -# Configure callback functionality. + * \snippet qs_i2c_master_callback.c config_callback + * -# Register write complete callback. + * \snippet qs_i2c_master_callback.c callback_reg + * -# Enable write complete callback. + * \snippet qs_i2c_master_callback.c callback_en + * -# Create a packet to send to slave. + * \snippet qs_i2c_master_callback.c write_packet + * + * \section asfdoc_sam0_sercom_i2c_master_callback_use_case_implementation Implementation + * \subsection asfdoc_sam0_sercom_i2c_master_callback_use_case_code Code + * Add to user application \c main(): + * \snippet qs_i2c_master_callback.c while + * \subsection asfdoc_sam0_sercom_i2c_master_callback_use_case_implementation_workflow Workflow + * -# Write packet to slave. + * \snippet qs_i2c_master_callback.c write_packet + * -# Infinite while loop, while waiting for interaction with slave. + * \snippet qs_i2c_master_callback.c while + * + * \section asfdoc_sam0_sercom_i2c_master_callback_use_case_callback Callback + * Each time a packet is sent, the callback function will be called. + * + * \subsection asfdoc_sam0_sercom_i2c_master_callback_use_case_callback_workflow Workflow + * - Write complete callback: + * -# Send every other packet in reversed order. + * \snippet qs_i2c_master_callback.c revert_order + * -# Write new packet to slave. + * \snippet qs_i2c_master_callback.c write_packet + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#include +#include + diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/i2c/quick_start_master_dma/qs_i2c_master_dma.h b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/i2c/quick_start_master_dma/qs_i2c_master_dma.h new file mode 100644 index 000000000..fe19ae2ea --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/i2c/quick_start_master_dma/qs_i2c_master_dma.h @@ -0,0 +1,164 @@ +/** + * \file + * + * \brief SAM SERCOM I2C Master Driver with DMA Quick Start Guide + * + * Copyright (c) 2014-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ + +/** + * \page asfdoc_sam0_sercom_i2c_master_dma_use_case Quick Start Guide for Using DMA with SERCOM I2C Master + * + * The supported board list: + * - SAMD21 Xplained Pro + * - SAMR21 Xplained Pro + * - SAML21 Xplained Pro + * - SAML22 Xplained Pro + * - SAMDA1 Xplained Pro + * - SAMC21 Xplained Pro + * - SAMHA1G16A Xplained Pro + * + * In this use case, the I2C will used and set up as follows: + * - Master mode + * - 100KHz operation speed + * - Not operational in standby + * - 10000 packet timeout value + * - 65535 unknown bus state timeout value + * + * + * \section asfdoc_sam0_sercom_i2c_master_dma_use_case_prereq Prerequisites + * The device must be connected to an I2C slave. + * + * \section asfdoc_sam0_sercom_i2c_master_dma_use_setup Setup + * + * \subsection asfdoc_sam0_sercom_i2c_master_dma_use_setup_code Code + * The following must be added to the user application: + * + * - A sample buffer to send, number of entries to send and address of slave: + * \snippet qs_i2c_master_dma.c packet_data + * + * Number of times to try to send packet if it fails: + * \snippet qs_i2c_master_dma.c timeout + * + * - Globally accessible module structure: + * \snippet qs_i2c_master_dma.c dev_i2c_inst + * + * - Function for setting up the module: + * \snippet qs_i2c_master_dma.c initialize_i2c + * + * - Globally accessible DMA module structure: + * \snippet qs_i2c_master_dma.c dma_resource + * + * - Globally transfer done flag: + * \snippet qs_i2c_master_dma.c transfer_done_flag + * + * - Globally accessible DMA transfer descriptor: + * \snippet qs_i2c_master_dma.c transfer_descriptor + * + * - Function for transfer done callback: + * \snippet qs_i2c_master_dma.c transfer_done + * + * - Function for setting up the DMA resource: + * \snippet qs_i2c_master_dma.c config_dma_resource + * + * - Function for setting up the DMA transfer descriptor: + * \snippet qs_i2c_master_dma.c setup_dma_transfer_descriptor + * - Add to user application \c main(): + * \snippet qs_i2c_master_dma.c init + * + * \subsection asfdoc_sam0_sercom_i2c_master_dma_use_setup_workflow Workflow + * -# Configure and enable module: + * \snippet qs_i2c_master_dma.c config_i2c + * -# Create and initialize configuration structure. + * \snippet qs_i2c_master_dma.c init_conf + * -# Change settings in the configuration. + * \snippet qs_i2c_master_dma.c conf_change + * -# Initialize the module with the set configurations. + * \snippet qs_i2c_master_dma.c init_module + * -# Enable the module. + * \snippet qs_i2c_master_dma.c enable_module + * + * -# Configure DMA + * -# Create a DMA resource configuration structure, which can be filled out to + * adjust the configuration of a single DMA transfer. + * \snippet qs_i2c_master_dma.c dma_setup_1 + * + * -# Initialize the DMA resource configuration struct with the module's + * default values. + * \snippet qs_i2c_master_dma.c dma_setup_2 + * \note This should always be performed before using the configuration + * struct to ensure that all values are initialized to known default + * settings. + * + * -# Set extra configurations for the DMA resource. It is using peripheral + * trigger. SERCOM TX trigger causes a transaction transfer in + * this example. + * \snippet qs_i2c_master_dma.c dma_setup_3 + * + * -# Allocate a DMA resource with the configurations. + * \snippet qs_i2c_master_dma.c dma_setup_4 + * + * -# Create a DMA transfer descriptor configuration structure, which can be + * filled out to adjust the configuration of a single DMA transfer. + * \snippet qs_i2c_master_dma.c dma_setup_5 + * + * -# Initialize the DMA transfer descriptor configuration struct with the module's + * default values. + * \snippet qs_i2c_master_dma.c dma_setup_6 + * \note This should always be performed before using the configuration + * struct to ensure that all values are initialized to known default + * settings. + * + * -# Set the specific parameters for a DMA transfer with transfer size, source + * address, and destination address. + * \snippet qs_i2c_master_dma.c dma_setup_7 + * + * -# Create the DMA transfer descriptor. + * \snippet qs_i2c_master_dma.c dma_setup_8 + * + * \section asfdoc_sam0_sercom_i2c_master_dma_use_implemenation Implementation + * \subsection asfdoc_sam0_sercom_i2c_master_dma_use_implemenation_code Code + * Add to user application \c main(): + * \snippet qs_i2c_master_dma.c main + * + * \subsection asfdoc_sam0_sercom_i2c_master_dma_use_implemenation_workflow Workflow + * -# Start the DMA transfer job. + * \snippet qs_i2c_master_dma.c start_transfer_job + * + * -# Set the auto address length and enable flag. + * \snippet qs_i2c_master_dma.c set_i2c_addr + * + * -# Waiting for transfer complete. + * \snippet qs_i2c_master_dma.c waiting_for_complete + * + * -# Enter an infinite loop once transfer complete. + * \snippet qs_i2c_master_dma.c inf_loop + */ +/* + * Support and FAQ: visit Microchip Support + */ diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/sercom.c b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/sercom.c new file mode 100644 index 000000000..0bcaa5899 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/sercom.c @@ -0,0 +1,280 @@ +/** + * \file + * + * \brief SAM Serial Peripheral Interface Driver + * + * Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#include "sercom.h" + +#define SHIFT 32 +#define BAUD_INT_MAX 8192 +#define BAUD_FP_MAX 8 + +#if !defined(__DOXYGEN__) +/** + * \internal Configuration structure to save current gclk status. + */ +struct _sercom_conf { + /* Status of gclk generator initialization */ + bool generator_is_set; + /* Sercom gclk generator used */ + enum gclk_generator generator_source; +}; + +static struct _sercom_conf _sercom_config; + + +/** + * \internal Calculate 64 bit division, ref can be found in + * http://en.wikipedia.org/wiki/Division_algorithm#Long_division + */ +static uint64_t long_division(uint64_t n, uint64_t d) +{ + int32_t i; + uint64_t q = 0, r = 0, bit_shift; + for (i = 63; i >= 0; i--) { + bit_shift = (uint64_t)1 << i; + + r = r << 1; + + if (n & bit_shift) { + r |= 0x01; + } + + if (r >= d) { + r = r - d; + q |= bit_shift; + } + } + + return q; +} + +/** + * \internal Calculate synchronous baudrate value (SPI/UART) + */ +enum status_code _sercom_get_sync_baud_val( + const uint32_t baudrate, + const uint32_t external_clock, + uint16_t *const baudvalue) +{ + /* Baud value variable */ + uint16_t baud_calculated = 0; + uint32_t clock_value = external_clock; + + + /* Check if baudrate is outside of valid range */ + if (baudrate > (external_clock / 2)) { + /* Return with error code */ + return STATUS_ERR_BAUDRATE_UNAVAILABLE; + } + + /* Calculate BAUD value from clock frequency and baudrate */ + clock_value = external_clock / 2; + while (clock_value >= baudrate) { + clock_value = clock_value - baudrate; + baud_calculated++; + } + baud_calculated = baud_calculated - 1; + + /* Check if BAUD value is more than 255, which is maximum + * for synchronous mode */ + if (baud_calculated > 0xFF) { + /* Return with an error code */ + return STATUS_ERR_BAUDRATE_UNAVAILABLE; + } else { + *baudvalue = baud_calculated; + return STATUS_OK; + } +} + +/** + * \internal Calculate asynchronous baudrate value (UART) +*/ +enum status_code _sercom_get_async_baud_val( + const uint32_t baudrate, + const uint32_t peripheral_clock, + uint16_t *const baudval, + enum sercom_asynchronous_operation_mode mode, + enum sercom_asynchronous_sample_num sample_num) +{ + /* Temporary variables */ + uint64_t ratio = 0; + uint64_t scale = 0; + uint64_t baud_calculated = 0; + uint8_t baud_fp; + uint32_t baud_int = 0; + uint64_t temp1; + + /* Check if the baudrate is outside of valid range */ + if ((baudrate * sample_num) > peripheral_clock) { + /* Return with error code */ + return STATUS_ERR_BAUDRATE_UNAVAILABLE; + } + + if(mode == SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC) { + /* Calculate the BAUD value */ + temp1 = ((sample_num * (uint64_t)baudrate) << SHIFT); + ratio = long_division(temp1, peripheral_clock); + scale = ((uint64_t)1 << SHIFT) - ratio; + baud_calculated = (65536 * scale) >> SHIFT; + } else if(mode == SERCOM_ASYNC_OPERATION_MODE_FRACTIONAL) { + temp1 = ((uint64_t)baudrate * sample_num); + baud_int = long_division( peripheral_clock, temp1); + if(baud_int > BAUD_INT_MAX) { + return STATUS_ERR_BAUDRATE_UNAVAILABLE; + } + temp1 = long_division( 8 * (uint64_t)peripheral_clock, temp1); + baud_fp = temp1 - 8 * baud_int; + baud_calculated = baud_int | (baud_fp << 13); + } + + *baudval = baud_calculated; + return STATUS_OK; +} +#endif + +/** + * \brief Set GCLK channel to generator. + * + * This will set the appropriate GCLK channel to the requested GCLK generator. + * This will set the generator for all SERCOM instances, and the user will thus + * only be able to set the same generator that has previously been set, if any. + * + * After the generator has been set the first time, the generator can be changed + * using the \c force_change flag. + * + * \param[in] generator_source The generator to use for SERCOM. + * \param[in] force_change Force change the generator. + * + * \return Status code indicating the GCLK generator change operation. + * \retval STATUS_OK If the generator update request was + * successful. + * \retval STATUS_ERR_ALREADY_INITIALIZED If a generator was already configured + * and the new configuration was not + * forced. + */ +enum status_code sercom_set_gclk_generator( + const enum gclk_generator generator_source, + const bool force_change) +{ + /* Check if valid option */ + if (!_sercom_config.generator_is_set || force_change) { + /* Create and fill a GCLK configuration structure for the new config */ + struct system_gclk_chan_config gclk_chan_conf; + system_gclk_chan_get_config_defaults(&gclk_chan_conf); + gclk_chan_conf.source_generator = generator_source; + system_gclk_chan_set_config(SERCOM_GCLK_ID, &gclk_chan_conf); + system_gclk_chan_enable(SERCOM_GCLK_ID); + + /* Save config */ + _sercom_config.generator_source = generator_source; + _sercom_config.generator_is_set = true; + + return STATUS_OK; + } else if (generator_source == _sercom_config.generator_source) { + /* Return status OK if same config */ + return STATUS_OK; + } + + /* Return invalid config to already initialized GCLK */ + return STATUS_ERR_ALREADY_INITIALIZED; +} + +/** \internal + * Creates a switch statement case entry to convert a SERCOM instance and pad + * index to the default SERCOM pad MUX setting. + */ +#define _SERCOM_PAD_DEFAULTS_CASE(n, pad) \ + case (uintptr_t)SERCOM##n: \ + switch (pad) { \ + case 0: \ + return SERCOM##n##_PAD0_DEFAULT; \ + case 1: \ + return SERCOM##n##_PAD1_DEFAULT; \ + case 2: \ + return SERCOM##n##_PAD2_DEFAULT; \ + case 3: \ + return SERCOM##n##_PAD3_DEFAULT; \ + } \ + break; + +/** + * \internal Gets the default PAD pinout for a given SERCOM. + * + * Returns the pinmux settings for the given SERCOM and pad. This is used + * for default configuration of pins. + * + * \param[in] sercom_module Pointer to the SERCOM module + * \param[in] pad PAD to get default pinout for + * + * \returns The default pinmux for the given SERCOM instance and PAD + * + */ +uint32_t _sercom_get_default_pad( + Sercom *const sercom_module, + const uint8_t pad) +{ + switch ((uintptr_t)sercom_module) { + /* Auto-generate a lookup table for the default SERCOM pad defaults */ + MREPEAT(SERCOM_INST_NUM, _SERCOM_PAD_DEFAULTS_CASE, pad) + } + + Assert(false); + return 0; +} + +/** + * \internal + * Find index of given instance. + * + * \param[in] sercom_instance Instance pointer. + * + * \return Index of given instance. + */ +uint8_t _sercom_get_sercom_inst_index( + Sercom *const sercom_instance) +{ + /* Save all available SERCOM instances for compare */ + Sercom *sercom_instances[SERCOM_INST_NUM] = SERCOM_INSTS; + + /* Find index for sercom instance */ + for (uint32_t i = 0; i < SERCOM_INST_NUM; i++) { + if ((uintptr_t)sercom_instance == (uintptr_t)sercom_instances[i]) { + return i; + } + } + + /* Invalid data given */ + Assert(false); + return 0; +} diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/sercom.h b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/sercom.h new file mode 100644 index 000000000..7ac19638d --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/sercom.h @@ -0,0 +1,108 @@ +/** + * \file + * + * \brief SAM Serial Peripheral Interface Driver + * + * Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#ifndef SERCOM_H_INCLUDED +#define SERCOM_H_INCLUDED + +#include +#include +#include +#include +#include "sercom_pinout.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* SERCOM modules should share same slow GCLK channel ID */ +#define SERCOM_GCLK_ID SERCOM0_GCLK_ID_SLOW + +#if (0x1ff >= REV_SERCOM) +# define FEATURE_SERCOM_SYNCBUSY_SCHEME_VERSION_1 +#elif (0x400 >= REV_SERCOM) +# define FEATURE_SERCOM_SYNCBUSY_SCHEME_VERSION_2 +#else +# error "Unknown SYNCBUSY scheme for this SERCOM revision" +#endif + +/** + * \brief sercom asynchronous operation mode + * + * Select sercom asynchronous operation mode + */ +enum sercom_asynchronous_operation_mode { + SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC = 0, + SERCOM_ASYNC_OPERATION_MODE_FRACTIONAL, +}; + +/** + * \brief sercom asynchronous samples per bit + * + * Select number of samples per bit + */ +enum sercom_asynchronous_sample_num { + SERCOM_ASYNC_SAMPLE_NUM_3 = 3, + SERCOM_ASYNC_SAMPLE_NUM_8 = 8, + SERCOM_ASYNC_SAMPLE_NUM_16 = 16, +}; + +enum status_code sercom_set_gclk_generator( + const enum gclk_generator generator_source, + const bool force_change); + +enum status_code _sercom_get_sync_baud_val( + const uint32_t baudrate, + const uint32_t external_clock, + uint16_t *const baudval); + +enum status_code _sercom_get_async_baud_val( + const uint32_t baudrate, + const uint32_t peripheral_clock, + uint16_t *const baudval, + enum sercom_asynchronous_operation_mode mode, + enum sercom_asynchronous_sample_num sample_num); + +uint32_t _sercom_get_default_pad( + Sercom *const sercom_module, + const uint8_t pad); + +uint8_t _sercom_get_sercom_inst_index( + Sercom *const sercom_instance); +#ifdef __cplusplus +} +#endif + +#endif //__SERCOM_H_INCLUDED diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/sercom_interrupt.c b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/sercom_interrupt.c new file mode 100644 index 000000000..1c14ebec9 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/sercom_interrupt.c @@ -0,0 +1,131 @@ +/** + * \file + * + * \brief SAM Serial Peripheral Interface Driver + * + * Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#include "sercom_interrupt.h" + +void *_sercom_instances[SERCOM_INST_NUM]; + +/** Save status of initialized handlers */ +static bool _handler_table_initialized = false; + +/** Void pointers for saving device instance structures */ +static void (*_sercom_interrupt_handlers[SERCOM_INST_NUM])(const uint8_t instance); + +/** + * \internal + * Default interrupt handler. + * + * \param[in] instance SERCOM instance used. + */ +static void _sercom_default_handler( + const uint8_t instance) +{ + Assert(false); +} + +/** + * \internal + * Saves the given callback handler. + * + * \param[in] instance Instance index. + * \param[in] interrupt_handler Pointer to instance callback handler. + */ +void _sercom_set_handler( + const uint8_t instance, + const sercom_handler_t interrupt_handler) +{ + /* Initialize handlers with default handler and device instances with 0 */ + if (_handler_table_initialized == false) { + for (uint32_t i = 0; i < SERCOM_INST_NUM; i++) { + _sercom_interrupt_handlers[i] = &_sercom_default_handler; + _sercom_instances[i] = NULL; + } + + _handler_table_initialized = true; + } + + /* Save interrupt handler */ + _sercom_interrupt_handlers[instance] = interrupt_handler; +} + + +/** \internal + * Converts a given SERCOM index to its interrupt vector index. + */ +#define _SERCOM_INTERRUPT_VECT_NUM(n, unused) \ + SYSTEM_INTERRUPT_MODULE_SERCOM##n, + +/** \internal + * Generates a SERCOM interrupt handler function for a given SERCOM index. + */ +#define _SERCOM_INTERRUPT_HANDLER(n, unused) \ + void SERCOM##n##_Handler(void) \ + { \ + _sercom_interrupt_handlers[n](n); \ + } + +/** + * \internal + * Returns the system interrupt vector. + * + * \param[in] sercom_instance Instance pointer + * + * \return Enum of system interrupt vector + * \retval SYSTEM_INTERRUPT_MODULE_SERCOM0 + * \retval SYSTEM_INTERRUPT_MODULE_SERCOM1 + * \retval SYSTEM_INTERRUPT_MODULE_SERCOM2 + * \retval SYSTEM_INTERRUPT_MODULE_SERCOM3 + * \retval SYSTEM_INTERRUPT_MODULE_SERCOM4 + * \retval SYSTEM_INTERRUPT_MODULE_SERCOM5 + * \retval SYSTEM_INTERRUPT_MODULE_SERCOM6 + * \retval SYSTEM_INTERRUPT_MODULE_SERCOM7 + */ +enum system_interrupt_vector _sercom_get_interrupt_vector( + Sercom *const sercom_instance) +{ + const uint8_t sercom_int_vectors[SERCOM_INST_NUM] = + { + MREPEAT(SERCOM_INST_NUM, _SERCOM_INTERRUPT_VECT_NUM, ~) + }; + + /* Retrieve the index of the SERCOM being requested */ + uint8_t instance_index = _sercom_get_sercom_inst_index(sercom_instance); + + /* Get the vector number from the lookup table for the requested SERCOM */ + return (enum system_interrupt_vector)sercom_int_vectors[instance_index]; +} + +/** Auto-generate a set of interrupt handlers for each SERCOM in the device */ +MREPEAT(SERCOM_INST_NUM, _SERCOM_INTERRUPT_HANDLER, ~) diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/sercom_interrupt.h b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/sercom_interrupt.h new file mode 100644 index 000000000..9bd9c7a3e --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/sercom_interrupt.h @@ -0,0 +1,62 @@ +/** + * \file + * + * \brief SAM Serial Peripheral Interface Driver + * + * Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#ifndef SERCOM_INTERRUPT_H_INCLUDED +#define SERCOM_INTERRUPT_H_INCLUDED + +#include "sercom.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Look-up table for device instances */ +extern void *_sercom_instances[SERCOM_INST_NUM]; + +typedef void (*sercom_handler_t)(uint8_t instance); + +enum system_interrupt_vector _sercom_get_interrupt_vector( + Sercom *const sercom_instance); + +void _sercom_set_handler( + const uint8_t instance, + const sercom_handler_t interrupt_handler); + +#ifdef __cplusplus +} +#endif + +#endif /* SERCOM_INTERRUPT_H_INCLUDED */ diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/sercom_pinout.h b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/sercom_pinout.h new file mode 100644 index 000000000..d7eb27e7c --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/sercom_pinout.h @@ -0,0 +1,612 @@ +/** + * \file + * + * \brief SAM SERCOM Module Pinout Definitions + * + * + * Copyright (c) 2012-2020 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#ifndef SERCOM_PINOUT_H_INCLUDED +#define SERCOM_PINOUT_H_INCLUDED + +#include + +#if SAMR21E + /* SERCOM0 */ + #define SERCOM0_PAD0_DEFAULT PINMUX_PA08C_SERCOM0_PAD0 + #define SERCOM0_PAD1_DEFAULT PINMUX_PA09C_SERCOM0_PAD1 + #define SERCOM0_PAD2_DEFAULT PINMUX_PA06D_SERCOM0_PAD2 + #define SERCOM0_PAD3_DEFAULT PINMUX_PA07D_SERCOM0_PAD3 + + /* SERCOM1 */ + #define SERCOM1_PAD0_DEFAULT PINMUX_PA16C_SERCOM1_PAD0 + #define SERCOM1_PAD1_DEFAULT PINMUX_PA17C_SERCOM1_PAD1 + #define SERCOM1_PAD2_DEFAULT PINMUX_PA18C_SERCOM1_PAD2 + #define SERCOM1_PAD3_DEFAULT PINMUX_PA19C_SERCOM1_PAD3 + + /* SERCOM2 */ + #define SERCOM2_PAD0_DEFAULT PINMUX_PA08D_SERCOM2_PAD0 + #define SERCOM2_PAD1_DEFAULT PINMUX_PA09D_SERCOM2_PAD1 + #define SERCOM2_PAD2_DEFAULT PINMUX_PA14C_SERCOM2_PAD2 + #define SERCOM2_PAD3_DEFAULT PINMUX_PA15C_SERCOM2_PAD3 + + /* SERCOM3 */ +# if SAM_PART_IS_DEFINED(SAMR21E19A) + #define SERCOM3_PAD0_DEFAULT PINMUX_PA16D_SERCOM3_PAD0 + #define SERCOM3_PAD1_DEFAULT PINMUX_PA17D_SERCOM3_PAD1 +# else + #define SERCOM3_PAD0_DEFAULT PINMUX_PA27F_SERCOM3_PAD0 + #define SERCOM3_PAD1_DEFAULT PINMUX_PA28F_SERCOM3_PAD1 +#endif + #define SERCOM3_PAD2_DEFAULT PINMUX_PA24C_SERCOM3_PAD2 + #define SERCOM3_PAD3_DEFAULT PINMUX_PA25C_SERCOM3_PAD3 + + /* SERCOM4 */ +# if SAM_PART_IS_DEFINED(SAMR21E19A) + #define SERCOM4_PAD0_DEFAULT PINMUX_PB08D_SERCOM4_PAD0 + #define SERCOM4_PAD1_DEFAULT PINMUX_PB09D_SERCOM4_PAD1 + #define SERCOM4_PAD2_DEFAULT PINMUX_PA14D_SERCOM4_PAD2 + #define SERCOM4_PAD3_DEFAULT PINMUX_PA15D_SERCOM4_PAD3 +# else + #define SERCOM4_PAD0_DEFAULT PINMUX_PC19F_SERCOM4_PAD0 + #define SERCOM4_PAD1_DEFAULT PINMUX_PB31F_SERCOM4_PAD1 + #define SERCOM4_PAD2_DEFAULT PINMUX_PB30F_SERCOM4_PAD2 + #define SERCOM4_PAD3_DEFAULT PINMUX_PC18F_SERCOM4_PAD3 +# endif + + /* SERCOM5 */ + #define SERCOM5_PAD0_DEFAULT PINMUX_PB30D_SERCOM5_PAD0 + #define SERCOM5_PAD1_DEFAULT PINMUX_PB31D_SERCOM5_PAD1 + #define SERCOM5_PAD2_DEFAULT PINMUX_PA24D_SERCOM5_PAD2 + #define SERCOM5_PAD3_DEFAULT PINMUX_PA25D_SERCOM5_PAD3 + +#elif SAMR21G + /* SERCOM0 */ + #define SERCOM0_PAD0_DEFAULT PINMUX_PA04D_SERCOM0_PAD0 + #define SERCOM0_PAD1_DEFAULT PINMUX_PA05D_SERCOM0_PAD1 + #define SERCOM0_PAD2_DEFAULT PINMUX_PA06D_SERCOM0_PAD2 + #define SERCOM0_PAD3_DEFAULT PINMUX_PA07D_SERCOM0_PAD3 + + /* SERCOM1 */ + #define SERCOM1_PAD0_DEFAULT PINMUX_PA00D_SERCOM1_PAD0 + #define SERCOM1_PAD1_DEFAULT PINMUX_PA01D_SERCOM1_PAD1 + #define SERCOM1_PAD2_DEFAULT PINMUX_PA30D_SERCOM1_PAD2 + #define SERCOM1_PAD3_DEFAULT PINMUX_PA31D_SERCOM1_PAD3 + + /* SERCOM2 */ + #define SERCOM2_PAD0_DEFAULT PINMUX_PA12C_SERCOM2_PAD0 + #define SERCOM2_PAD1_DEFAULT PINMUX_PA13C_SERCOM2_PAD1 + #define SERCOM2_PAD2_DEFAULT PINMUX_PA14C_SERCOM2_PAD2 + #define SERCOM2_PAD3_DEFAULT PINMUX_PA15C_SERCOM2_PAD3 + + /* SERCOM3 */ + #define SERCOM3_PAD0_DEFAULT PINMUX_PA16D_SERCOM3_PAD0 + #define SERCOM3_PAD1_DEFAULT PINMUX_PA17D_SERCOM3_PAD1 + #define SERCOM3_PAD2_DEFAULT PINMUX_PA18D_SERCOM3_PAD2 + #define SERCOM3_PAD3_DEFAULT PINMUX_PA19D_SERCOM3_PAD3 + + /* SERCOM4 */ + #define SERCOM4_PAD0_DEFAULT PINMUX_PC19F_SERCOM4_PAD0 + #define SERCOM4_PAD1_DEFAULT PINMUX_PB31F_SERCOM4_PAD1 + #define SERCOM4_PAD2_DEFAULT PINMUX_PB30F_SERCOM4_PAD2 + #define SERCOM4_PAD3_DEFAULT PINMUX_PC18F_SERCOM4_PAD3 + + /* SERCOM5 */ + #define SERCOM5_PAD0_DEFAULT PINMUX_PA22D_SERCOM5_PAD0 + #define SERCOM5_PAD1_DEFAULT PINMUX_PA23D_SERCOM5_PAD1 + #define SERCOM5_PAD2_DEFAULT PINMUX_PA24D_SERCOM5_PAD2 + #define SERCOM5_PAD3_DEFAULT PINMUX_PA25D_SERCOM5_PAD3 + +#elif (SAMD09) + /* SERCOM0 */ + #define SERCOM0_PAD0_DEFAULT PINMUX_PA04D_SERCOM0_PAD0 + #define SERCOM0_PAD1_DEFAULT PINMUX_PA05D_SERCOM0_PAD1 + #define SERCOM0_PAD2_DEFAULT PINMUX_PA08D_SERCOM0_PAD2 + #define SERCOM0_PAD3_DEFAULT PINMUX_PA09D_SERCOM0_PAD3 + + /* SERCOM1 */ + #define SERCOM1_PAD0_DEFAULT PINMUX_PA30C_SERCOM1_PAD0 + #define SERCOM1_PAD1_DEFAULT PINMUX_PA31C_SERCOM1_PAD1 + #define SERCOM1_PAD2_DEFAULT PINMUX_PA24C_SERCOM1_PAD2 + #define SERCOM1_PAD3_DEFAULT PINMUX_PA25C_SERCOM1_PAD3 + +#elif (SAMD10DS) || (SAMD10DM) || (SAMD10DU) || (SAMD11DS) || (SAMD11DM) || (SAMD11DU) + /* SERCOM0 */ + #define SERCOM0_PAD0_DEFAULT PINMUX_PA04D_SERCOM0_PAD0 + #define SERCOM0_PAD1_DEFAULT PINMUX_PA05D_SERCOM0_PAD1 + #define SERCOM0_PAD2_DEFAULT PINMUX_PA06D_SERCOM0_PAD2 + #define SERCOM0_PAD3_DEFAULT PINMUX_PA07D_SERCOM0_PAD3 + + /* SERCOM1 */ + #define SERCOM1_PAD0_DEFAULT PINMUX_PA22C_SERCOM1_PAD0 + #define SERCOM1_PAD1_DEFAULT PINMUX_PA23C_SERCOM1_PAD1 + #define SERCOM1_PAD2_DEFAULT PINMUX_PA30D_SERCOM1_PAD2 + #define SERCOM1_PAD3_DEFAULT PINMUX_PA31D_SERCOM1_PAD3 + + /* SERCOM2 */ + #define SERCOM2_PAD0_DEFAULT PINMUX_PA22D_SERCOM2_PAD0 + #define SERCOM2_PAD1_DEFAULT PINMUX_PA23D_SERCOM2_PAD1 + #define SERCOM2_PAD2_DEFAULT PINMUX_PA16D_SERCOM2_PAD2 + #define SERCOM2_PAD3_DEFAULT PINMUX_PA25D_SERCOM2_PAD3 + +#elif (SAMD10C) || (SAMD11C) + /* SERCOM0 */ + #define SERCOM0_PAD0_DEFAULT PINMUX_PA04D_SERCOM0_PAD0 + #define SERCOM0_PAD1_DEFAULT PINMUX_PA05D_SERCOM0_PAD1 + #define SERCOM0_PAD2_DEFAULT PINMUX_PA08D_SERCOM0_PAD2 + #define SERCOM0_PAD3_DEFAULT PINMUX_PA09D_SERCOM0_PAD3 + + /* SERCOM1 */ + #define SERCOM1_PAD0_DEFAULT PINMUX_PA30C_SERCOM1_PAD0 + #define SERCOM1_PAD1_DEFAULT PINMUX_PA31C_SERCOM1_PAD1 + #define SERCOM1_PAD2_DEFAULT PINMUX_PA24C_SERCOM1_PAD2 + #define SERCOM1_PAD3_DEFAULT PINMUX_PA25C_SERCOM1_PAD3 + +#elif SAM_PART_IS_DEFINED(SAMD21E15L) || SAM_PART_IS_DEFINED(SAMD21E16L) + + /* SERCOM0 */ + #define SERCOM0_PAD0_DEFAULT PINMUX_PA04D_SERCOM0_PAD0 + #define SERCOM0_PAD1_DEFAULT PINMUX_PA05D_SERCOM0_PAD1 + #define SERCOM0_PAD2_DEFAULT PINMUX_PA06D_SERCOM0_PAD2 + #define SERCOM0_PAD3_DEFAULT PINMUX_PA07D_SERCOM0_PAD3 + + /* SERCOM1 */ + #define SERCOM1_PAD0_DEFAULT PINMUX_PA16C_SERCOM1_PAD0 + #define SERCOM1_PAD1_DEFAULT PINMUX_PA17C_SERCOM1_PAD1 + #define SERCOM1_PAD2_DEFAULT PINMUX_PA18C_SERCOM1_PAD2 + #define SERCOM1_PAD3_DEFAULT PINMUX_PA19C_SERCOM1_PAD3 + + /* SERCOM2 */ + #define SERCOM2_PAD0_DEFAULT PINMUX_PA08D_SERCOM2_PAD0 + #define SERCOM2_PAD1_DEFAULT PINMUX_PA09D_SERCOM2_PAD1 + #define SERCOM2_PAD2_DEFAULT PINMUX_PA10D_SERCOM2_PAD2 + #define SERCOM2_PAD3_DEFAULT PINMUX_PA11D_SERCOM2_PAD3 + + /* SERCOM3 */ + #define SERCOM3_PAD0_DEFAULT PINMUX_PA22C_SERCOM3_PAD0 + #define SERCOM3_PAD1_DEFAULT PINMUX_PA23C_SERCOM3_PAD1 + #define SERCOM3_PAD2_DEFAULT PINMUX_PA24C_SERCOM3_PAD2 + #define SERCOM3_PAD3_DEFAULT PINMUX_PA25C_SERCOM3_PAD3 + +#elif (SAML22N) + /* SERCOM0 */ + #define SERCOM0_PAD0_DEFAULT PINMUX_PA08C_SERCOM0_PAD0 + #define SERCOM0_PAD1_DEFAULT PINMUX_PA09C_SERCOM0_PAD1 + #define SERCOM0_PAD2_DEFAULT PINMUX_PA10C_SERCOM0_PAD2 + #define SERCOM0_PAD3_DEFAULT PINMUX_PA11C_SERCOM0_PAD3 + + /* SERCOM1 */ + #define SERCOM1_PAD0_DEFAULT PINMUX_PA16C_SERCOM1_PAD0 + #define SERCOM1_PAD1_DEFAULT PINMUX_PA17C_SERCOM1_PAD1 + #define SERCOM1_PAD2_DEFAULT PINMUX_PA18C_SERCOM1_PAD2 + #define SERCOM1_PAD3_DEFAULT PINMUX_PA19C_SERCOM1_PAD3 + + /* SERCOM2 */ + #define SERCOM2_PAD0_DEFAULT PINMUX_PA22D_SERCOM2_PAD0 + #define SERCOM2_PAD1_DEFAULT PINMUX_PA23D_SERCOM2_PAD1 + #define SERCOM2_PAD2_DEFAULT PINMUX_PA20D_SERCOM2_PAD2 + #define SERCOM2_PAD3_DEFAULT PINMUX_PA21D_SERCOM2_PAD3 + + /* SERCOM3 */ + #define SERCOM3_PAD0_DEFAULT PINMUX_PB02C_SERCOM3_PAD0 + #define SERCOM3_PAD1_DEFAULT PINMUX_PB21C_SERCOM3_PAD1 + #define SERCOM3_PAD2_DEFAULT PINMUX_PB00C_SERCOM3_PAD2 + #define SERCOM3_PAD3_DEFAULT PINMUX_PB01C_SERCOM3_PAD3 + + /* SERCOM4 */ + #define SERCOM4_PAD0_DEFAULT PINMUX_PA12C_SERCOM4_PAD0 + #define SERCOM4_PAD1_DEFAULT PINMUX_PA13C_SERCOM4_PAD1 + #define SERCOM4_PAD2_DEFAULT PINMUX_PA14C_SERCOM4_PAD2 + #define SERCOM4_PAD3_DEFAULT PINMUX_PA15C_SERCOM4_PAD3 + + /* SERCOM5 */ + #define SERCOM5_PAD0_DEFAULT PINMUX_PB30D_SERCOM5_PAD0 + #define SERCOM5_PAD1_DEFAULT PINMUX_PB31D_SERCOM5_PAD1 + #define SERCOM5_PAD2_DEFAULT PINMUX_PB22D_SERCOM5_PAD2 + #define SERCOM5_PAD3_DEFAULT PINMUX_PB23D_SERCOM5_PAD3 +#elif (SAML22J) || (SAML22G) + /* SERCOM0 */ + #define SERCOM0_PAD0_DEFAULT PINMUX_PA08C_SERCOM0_PAD0 + #define SERCOM0_PAD1_DEFAULT PINMUX_PA09C_SERCOM0_PAD1 + #define SERCOM0_PAD2_DEFAULT PINMUX_PA10C_SERCOM0_PAD2 + #define SERCOM0_PAD3_DEFAULT PINMUX_PA11C_SERCOM0_PAD3 + + /* SERCOM1 */ + #define SERCOM1_PAD0_DEFAULT PINMUX_PA16C_SERCOM1_PAD0 + #define SERCOM1_PAD1_DEFAULT PINMUX_PA17C_SERCOM1_PAD1 + #define SERCOM1_PAD2_DEFAULT PINMUX_PA18C_SERCOM1_PAD2 + #define SERCOM1_PAD3_DEFAULT PINMUX_PA19C_SERCOM1_PAD3 + + /* SERCOM2 */ + #define SERCOM2_PAD0_DEFAULT PINMUX_PA22D_SERCOM2_PAD0 + #define SERCOM2_PAD1_DEFAULT PINMUX_PA23D_SERCOM2_PAD1 + #define SERCOM2_PAD2_DEFAULT PINMUX_PA20D_SERCOM2_PAD2 + #define SERCOM2_PAD3_DEFAULT PINMUX_PA21D_SERCOM2_PAD3 + + /* SERCOM3 */ + #define SERCOM3_PAD0_DEFAULT PINMUX_PA12D_SERCOM3_PAD0 + #define SERCOM3_PAD1_DEFAULT PINMUX_PA13D_SERCOM3_PAD1 + #define SERCOM3_PAD2_DEFAULT PINMUX_PA14D_SERCOM3_PAD2 + #define SERCOM3_PAD3_DEFAULT PINMUX_PA15D_SERCOM3_PAD3 +#elif (SAMC20E) || (SAMC21E) + /* SERCOM0 */ + #define SERCOM0_PAD0_DEFAULT PINMUX_PA04D_SERCOM0_PAD0 + #define SERCOM0_PAD1_DEFAULT PINMUX_PA05D_SERCOM0_PAD1 + #define SERCOM0_PAD2_DEFAULT PINMUX_PA06D_SERCOM0_PAD2 + #define SERCOM0_PAD3_DEFAULT PINMUX_PA07D_SERCOM0_PAD3 + + /* SERCOM1 */ + #define SERCOM1_PAD0_DEFAULT PINMUX_PA16C_SERCOM1_PAD0 + #define SERCOM1_PAD1_DEFAULT PINMUX_PA17C_SERCOM1_PAD1 + #define SERCOM1_PAD2_DEFAULT PINMUX_PA18C_SERCOM1_PAD2 + #define SERCOM1_PAD3_DEFAULT PINMUX_PA19C_SERCOM1_PAD3 + + /* SERCOM2 */ + #define SERCOM2_PAD0_DEFAULT PINMUX_PA08D_SERCOM2_PAD0 + #define SERCOM2_PAD1_DEFAULT PINMUX_PA09D_SERCOM2_PAD1 + #define SERCOM2_PAD2_DEFAULT PINMUX_PA10D_SERCOM2_PAD2 + #define SERCOM2_PAD3_DEFAULT PINMUX_PA11D_SERCOM2_PAD3 + + /* SERCOM3 */ + #define SERCOM3_PAD0_DEFAULT PINMUX_PA22C_SERCOM3_PAD0 + #define SERCOM3_PAD1_DEFAULT PINMUX_PA23C_SERCOM3_PAD1 + #define SERCOM3_PAD2_DEFAULT PINMUX_PA24C_SERCOM3_PAD2 + #define SERCOM3_PAD3_DEFAULT PINMUX_PA25C_SERCOM3_PAD3 + +#elif (SAMC20G) || (SAMC21G) + /* SERCOM0 */ + #define SERCOM0_PAD0_DEFAULT PINMUX_PA04D_SERCOM0_PAD0 + #define SERCOM0_PAD1_DEFAULT PINMUX_PA05D_SERCOM0_PAD1 + #define SERCOM0_PAD2_DEFAULT PINMUX_PA06D_SERCOM0_PAD2 + #define SERCOM0_PAD3_DEFAULT PINMUX_PA07D_SERCOM0_PAD3 + + /* SERCOM1 */ + #define SERCOM1_PAD0_DEFAULT PINMUX_PA16C_SERCOM1_PAD0 + #define SERCOM1_PAD1_DEFAULT PINMUX_PA17C_SERCOM1_PAD1 + #define SERCOM1_PAD2_DEFAULT PINMUX_PA18C_SERCOM1_PAD2 + #define SERCOM1_PAD3_DEFAULT PINMUX_PA19C_SERCOM1_PAD3 + + /* SERCOM2 */ + #define SERCOM2_PAD0_DEFAULT PINMUX_PA12C_SERCOM2_PAD0 + #define SERCOM2_PAD1_DEFAULT PINMUX_PA13C_SERCOM2_PAD1 + #define SERCOM2_PAD2_DEFAULT PINMUX_PA14C_SERCOM2_PAD2 + #define SERCOM2_PAD3_DEFAULT PINMUX_PA15C_SERCOM2_PAD3 + + /* SERCOM3 */ + #define SERCOM3_PAD0_DEFAULT PINMUX_PA22C_SERCOM3_PAD0 + #define SERCOM3_PAD1_DEFAULT PINMUX_PA23C_SERCOM3_PAD1 + #define SERCOM3_PAD2_DEFAULT PINMUX_PA24C_SERCOM3_PAD2 + #define SERCOM3_PAD3_DEFAULT PINMUX_PA25C_SERCOM3_PAD3 + + #ifdef ID_SERCOM4 + /* SERCOM4 */ + #define SERCOM4_PAD0_DEFAULT PINMUX_PB08D_SERCOM4_PAD0 + #define SERCOM4_PAD1_DEFAULT PINMUX_PB09D_SERCOM4_PAD1 + #define SERCOM4_PAD2_DEFAULT PINMUX_PB10D_SERCOM4_PAD2 + #define SERCOM4_PAD3_DEFAULT PINMUX_PB11D_SERCOM4_PAD3 + #endif + + #ifdef ID_SERCOM5 + /* SERCOM5 */ + #define SERCOM5_PAD0_DEFAULT PINMUX_PB02D_SERCOM5_PAD0 + #define SERCOM5_PAD1_DEFAULT PINMUX_PB03D_SERCOM5_PAD1 + #define SERCOM5_PAD2_DEFAULT PINMUX_PB22D_SERCOM5_PAD2 + #define SERCOM5_PAD3_DEFAULT PINMUX_PB23D_SERCOM5_PAD3 + #endif + +#elif (SAMC20J) || (SAMC21J) + /* SERCOM0 */ + #define SERCOM0_PAD0_DEFAULT PINMUX_PA04D_SERCOM0_PAD0 + #define SERCOM0_PAD1_DEFAULT PINMUX_PA05D_SERCOM0_PAD1 + #define SERCOM0_PAD2_DEFAULT PINMUX_PA06D_SERCOM0_PAD2 + #define SERCOM0_PAD3_DEFAULT PINMUX_PA07D_SERCOM0_PAD3 + + /* SERCOM1 */ + #define SERCOM1_PAD0_DEFAULT PINMUX_PA16C_SERCOM1_PAD0 + #define SERCOM1_PAD1_DEFAULT PINMUX_PA17C_SERCOM1_PAD1 + #define SERCOM1_PAD2_DEFAULT PINMUX_PA18C_SERCOM1_PAD2 + #define SERCOM1_PAD3_DEFAULT PINMUX_PA19C_SERCOM1_PAD3 + + /* SERCOM2 */ + #define SERCOM2_PAD0_DEFAULT PINMUX_PA12C_SERCOM2_PAD0 + #define SERCOM2_PAD1_DEFAULT PINMUX_PA13C_SERCOM2_PAD1 + #define SERCOM2_PAD2_DEFAULT PINMUX_PA14C_SERCOM2_PAD2 + #define SERCOM2_PAD3_DEFAULT PINMUX_PA15C_SERCOM2_PAD3 + + /* SERCOM3 */ + #define SERCOM3_PAD0_DEFAULT PINMUX_PA22C_SERCOM3_PAD0 + #define SERCOM3_PAD1_DEFAULT PINMUX_PA23C_SERCOM3_PAD1 + #define SERCOM3_PAD2_DEFAULT PINMUX_PA24C_SERCOM3_PAD2 + #define SERCOM3_PAD3_DEFAULT PINMUX_PA25C_SERCOM3_PAD3 + + #ifdef ID_SERCOM4 + /* SERCOM4 */ + #define SERCOM4_PAD0_DEFAULT PINMUX_PB08D_SERCOM4_PAD0 + #define SERCOM4_PAD1_DEFAULT PINMUX_PB09D_SERCOM4_PAD1 + #define SERCOM4_PAD2_DEFAULT PINMUX_PB10D_SERCOM4_PAD2 + #define SERCOM4_PAD3_DEFAULT PINMUX_PB11D_SERCOM4_PAD3 + #endif + + #ifdef ID_SERCOM5 + /* SERCOM5 */ + #define SERCOM5_PAD0_DEFAULT PINMUX_PB02D_SERCOM5_PAD0 + #define SERCOM5_PAD1_DEFAULT PINMUX_PB03D_SERCOM5_PAD1 + #define SERCOM5_PAD2_DEFAULT PINMUX_PB00D_SERCOM5_PAD2 + #define SERCOM5_PAD3_DEFAULT PINMUX_PB01D_SERCOM5_PAD3 + #endif + +#elif (SAMDA1) + /* SERCOM0 */ + #define SERCOM0_PAD0_DEFAULT PINMUX_PA04D_SERCOM0_PAD0 + #define SERCOM0_PAD1_DEFAULT PINMUX_PA05D_SERCOM0_PAD1 + #define SERCOM0_PAD2_DEFAULT PINMUX_PA06D_SERCOM0_PAD2 + #define SERCOM0_PAD3_DEFAULT PINMUX_PA07D_SERCOM0_PAD3 + + /* SERCOM1 */ + #define SERCOM1_PAD0_DEFAULT PINMUX_PA00D_SERCOM1_PAD0 + #define SERCOM1_PAD1_DEFAULT PINMUX_PA01D_SERCOM1_PAD1 + #define SERCOM1_PAD2_DEFAULT PINMUX_PA30D_SERCOM1_PAD2 + #define SERCOM1_PAD3_DEFAULT PINMUX_PA31D_SERCOM1_PAD3 + + /* SERCOM2 */ + #define SERCOM2_PAD0_DEFAULT PINMUX_PA08D_SERCOM2_PAD0 + #define SERCOM2_PAD1_DEFAULT PINMUX_PA09D_SERCOM2_PAD1 + #define SERCOM2_PAD2_DEFAULT PINMUX_PA10D_SERCOM2_PAD2 + #define SERCOM2_PAD3_DEFAULT PINMUX_PA11D_SERCOM2_PAD3 + + /* SERCOM3 */ + #define SERCOM3_PAD0_DEFAULT PINMUX_PA16D_SERCOM3_PAD0 + #define SERCOM3_PAD1_DEFAULT PINMUX_PA17D_SERCOM3_PAD1 + #define SERCOM3_PAD2_DEFAULT PINMUX_PA18D_SERCOM3_PAD2 + #define SERCOM3_PAD3_DEFAULT PINMUX_PA19D_SERCOM3_PAD3 + + #if (SAMDA1E) + /* SERCOM4 */ + #define SERCOM4_PAD0_DEFAULT 0 /* No available pin */ + #define SERCOM4_PAD1_DEFAULT 0 /* No available pin */ + #define SERCOM4_PAD2_DEFAULT PINMUX_PA14D_SERCOM4_PAD2 + #define SERCOM4_PAD3_DEFAULT PINMUX_PA15D_SERCOM4_PAD3 + #else + /* SERCOM4 */ + #define SERCOM4_PAD0_DEFAULT PINMUX_PA12D_SERCOM4_PAD0 + #define SERCOM4_PAD1_DEFAULT PINMUX_PA13D_SERCOM4_PAD1 + #define SERCOM4_PAD2_DEFAULT PINMUX_PA14D_SERCOM4_PAD2 + #define SERCOM4_PAD3_DEFAULT PINMUX_PA15D_SERCOM4_PAD3 + #endif + + /* SERCOM5 */ + #define SERCOM5_PAD0_DEFAULT PINMUX_PA22D_SERCOM5_PAD0 + #define SERCOM5_PAD1_DEFAULT PINMUX_PA23D_SERCOM5_PAD1 + #define SERCOM5_PAD2_DEFAULT PINMUX_PA24D_SERCOM5_PAD2 + #define SERCOM5_PAD3_DEFAULT PINMUX_PA25D_SERCOM5_PAD3 + +#elif (SAMHA1E) || (SAMHA0E) + + /* SERCOM0 */ + #define SERCOM0_PAD0_DEFAULT PINMUX_PA08C_SERCOM0_PAD0 + #define SERCOM0_PAD1_DEFAULT PINMUX_PA09C_SERCOM0_PAD1 + #define SERCOM0_PAD2_DEFAULT PINMUX_PA06D_SERCOM0_PAD2 + #define SERCOM0_PAD3_DEFAULT PINMUX_PA07D_SERCOM0_PAD3 + + /* SERCOM1 */ + #define SERCOM1_PAD0_DEFAULT PINMUX_PA16C_SERCOM1_PAD0 + #define SERCOM1_PAD1_DEFAULT PINMUX_PA17C_SERCOM1_PAD1 + #define SERCOM1_PAD2_DEFAULT PINMUX_PA18C_SERCOM1_PAD2 + #define SERCOM1_PAD3_DEFAULT PINMUX_PA19C_SERCOM1_PAD3 + + /* SERCOM2 */ + #define SERCOM2_PAD0_DEFAULT PINMUX_PA08D_SERCOM2_PAD0 + #define SERCOM2_PAD1_DEFAULT PINMUX_PA09D_SERCOM2_PAD1 + #define SERCOM2_PAD2_DEFAULT PINMUX_PA14C_SERCOM2_PAD2 + #define SERCOM2_PAD3_DEFAULT PINMUX_PA15C_SERCOM2_PAD3 + + /* SERCOM3 */ + #define SERCOM3_PAD0_DEFAULT PINMUX_PA16D_SERCOM3_PAD0 + #define SERCOM3_PAD1_DEFAULT PINMUX_PA17D_SERCOM3_PAD1 + #define SERCOM3_PAD2_DEFAULT PINMUX_PA18D_SERCOM3_PAD2 + #define SERCOM3_PAD3_DEFAULT PINMUX_PA19D_SERCOM3_PAD3 + + /* SERCOM4 */ + #define SERCOM4_PAD0_DEFAULT 0 /* No available pin */ + #define SERCOM4_PAD1_DEFAULT PINMUX_PA13D_SERCOM4_PAD1 + #define SERCOM4_PAD2_DEFAULT PINMUX_PA14D_SERCOM4_PAD2 + #define SERCOM4_PAD3_DEFAULT PINMUX_PB11D_SERCOM4_PAD3 + + /* SERCOM5 */ + #define SERCOM5_PAD0_DEFAULT 0 /* No available pin */ + #define SERCOM5_PAD1_DEFAULT 0 /* No available pin */ + #define SERCOM5_PAD2_DEFAULT PINMUX_PA20C_SERCOM5_PAD2 + #define SERCOM5_PAD3_DEFAULT 0 /* No available pin */ + +#elif (SAMHA1G) || (SAMHA0G) + + /* SERCOM0 */ + #define SERCOM0_PAD0_DEFAULT PINMUX_PA04D_SERCOM0_PAD0 + #define SERCOM0_PAD1_DEFAULT PINMUX_PA05D_SERCOM0_PAD1 + #define SERCOM0_PAD2_DEFAULT PINMUX_PA10C_SERCOM0_PAD2 + #define SERCOM0_PAD3_DEFAULT PINMUX_PA11C_SERCOM0_PAD3 + + /* SERCOM1 */ + #define SERCOM1_PAD0_DEFAULT PINMUX_PA16C_SERCOM1_PAD0 + #define SERCOM1_PAD1_DEFAULT PINMUX_PA17C_SERCOM1_PAD1 + #define SERCOM1_PAD2_DEFAULT PINMUX_PA18C_SERCOM1_PAD2 + #define SERCOM1_PAD3_DEFAULT PINMUX_PA19C_SERCOM1_PAD3 + + /* SERCOM2 */ + #define SERCOM2_PAD0_DEFAULT PINMUX_PA08D_SERCOM2_PAD0 + #define SERCOM2_PAD1_DEFAULT PINMUX_PA09D_SERCOM2_PAD1 + #define SERCOM2_PAD2_DEFAULT PINMUX_PA14C_SERCOM2_PAD2 + #define SERCOM2_PAD3_DEFAULT PINMUX_PA15C_SERCOM2_PAD3 + + /* SERCOM3 */ + #define SERCOM3_PAD0_DEFAULT PINMUX_PA16D_SERCOM3_PAD0 + #define SERCOM3_PAD1_DEFAULT PINMUX_PA17D_SERCOM3_PAD1 + #define SERCOM3_PAD2_DEFAULT PINMUX_PA18D_SERCOM3_PAD2 + #define SERCOM3_PAD3_DEFAULT PINMUX_PA19D_SERCOM3_PAD3 + + /* SERCOM4 */ + #define SERCOM4_PAD0_DEFAULT 0 /* No available pin */ + #define SERCOM4_PAD1_DEFAULT 0 /* No available pin */ + #define SERCOM4_PAD2_DEFAULT PINMUX_PB10D_SERCOM4_PAD2 + #define SERCOM4_PAD3_DEFAULT PINMUX_PB11D_SERCOM4_PAD3 + + /* SERCOM5 */ + #define SERCOM5_PAD0_DEFAULT PINMUX_PB16C_SERCOM5_PAD0 + #define SERCOM5_PAD1_DEFAULT PINMUX_PB17C_SERCOM5_PAD1 + #define SERCOM5_PAD2_DEFAULT PINMUX_PA20C_SERCOM5_PAD2 + #define SERCOM5_PAD3_DEFAULT PINMUX_PA21C_SERCOM5_PAD3 + +#elif (SAML21E) || (SAMR34) || (SAMR35) || (WLR089) + + /* SERCOM0 */ + #define SERCOM0_PAD0_DEFAULT PINMUX_PA04D_SERCOM0_PAD0 + #define SERCOM0_PAD1_DEFAULT PINMUX_PA05D_SERCOM0_PAD1 + #define SERCOM0_PAD2_DEFAULT PINMUX_PA06D_SERCOM0_PAD2 + #define SERCOM0_PAD3_DEFAULT PINMUX_PA07D_SERCOM0_PAD3 + + /* SERCOM1 */ + #define SERCOM1_PAD0_DEFAULT PINMUX_PA00D_SERCOM1_PAD0 + #define SERCOM1_PAD1_DEFAULT PINMUX_PA01D_SERCOM1_PAD1 + #define SERCOM1_PAD2_DEFAULT PINMUX_PA30D_SERCOM1_PAD2 + #define SERCOM1_PAD3_DEFAULT PINMUX_PA31D_SERCOM1_PAD3 + + /* SERCOM2 */ + #define SERCOM2_PAD0_DEFAULT PINMUX_PA08D_SERCOM2_PAD0 + #define SERCOM2_PAD1_DEFAULT PINMUX_PA09D_SERCOM2_PAD1 + #define SERCOM2_PAD2_DEFAULT PINMUX_PA10D_SERCOM2_PAD2 + #define SERCOM2_PAD3_DEFAULT PINMUX_PA11D_SERCOM2_PAD3 + + /* SERCOM3 */ + #define SERCOM3_PAD0_DEFAULT PINMUX_PA16D_SERCOM3_PAD0 + #define SERCOM3_PAD1_DEFAULT PINMUX_PA17D_SERCOM3_PAD1 + #define SERCOM3_PAD2_DEFAULT PINMUX_PA18D_SERCOM3_PAD2 + #define SERCOM3_PAD3_DEFAULT PINMUX_PA19D_SERCOM3_PAD3 + + #if !SAM_PART_IS_DEFINED(SAML21E18A) + /* SERCOM4 */ + #define SERCOM4_PAD0_DEFAULT 0 /* No available pin */ + #define SERCOM4_PAD1_DEFAULT 0 /* No available pin */ + #define SERCOM4_PAD2_DEFAULT PINMUX_PA14D_SERCOM4_PAD2 + #define SERCOM4_PAD3_DEFAULT PINMUX_PA15D_SERCOM4_PAD3 + + /* SERCOM5 */ + #define SERCOM5_PAD0_DEFAULT PINMUX_PA22D_SERCOM5_PAD0 + #define SERCOM5_PAD1_DEFAULT PINMUX_PA23D_SERCOM5_PAD1 + #define SERCOM5_PAD2_DEFAULT PINMUX_PA24D_SERCOM5_PAD2 + #define SERCOM5_PAD3_DEFAULT PINMUX_PA25D_SERCOM5_PAD3 + #endif + +#elif (SAMR30E) + + /* SERCOM0 */ + #define SERCOM0_PAD0_DEFAULT 0 /* No available pin */ + #define SERCOM0_PAD1_DEFAULT 0 /* No available pin */ + #define SERCOM0_PAD2_DEFAULT PINMUX_PA06D_SERCOM0_PAD2 + #define SERCOM0_PAD3_DEFAULT PINMUX_PA07D_SERCOM0_PAD3 + + /* SERCOM1 */ + #define SERCOM1_PAD0_DEFAULT 0 /* No available pin */ + #define SERCOM1_PAD1_DEFAULT 0 /* No available pin */ + #define SERCOM1_PAD2_DEFAULT PINMUX_PA30D_SERCOM1_PAD2 + #define SERCOM1_PAD3_DEFAULT PINMUX_PA31D_SERCOM1_PAD3 + + /* SERCOM2 */ + #define SERCOM2_PAD0_DEFAULT PINMUX_PA08D_SERCOM2_PAD0 + #define SERCOM2_PAD1_DEFAULT PINMUX_PA09D_SERCOM2_PAD1 + #define SERCOM2_PAD2_DEFAULT 0 /* No available pin */ + #define SERCOM2_PAD3_DEFAULT 0 /* No available pin */ + + /* SERCOM3 */ + #define SERCOM3_PAD0_DEFAULT PINMUX_PA16D_SERCOM3_PAD0 + #define SERCOM3_PAD1_DEFAULT PINMUX_PA17D_SERCOM3_PAD1 + #define SERCOM3_PAD2_DEFAULT PINMUX_PA18D_SERCOM3_PAD2 + #define SERCOM3_PAD3_DEFAULT PINMUX_PA19D_SERCOM3_PAD3 + + /* SERCOM4 */ + #define SERCOM4_PAD0_DEFAULT 0 /* No available pin */ + #define SERCOM4_PAD1_DEFAULT 0 /* No available pin */ + #define SERCOM4_PAD2_DEFAULT PINMUX_PA14D_SERCOM4_PAD2 + #define SERCOM4_PAD3_DEFAULT PINMUX_PA15D_SERCOM4_PAD3 + + /* SERCOM5 */ + #define SERCOM5_PAD0_DEFAULT 0 + #define SERCOM5_PAD1_DEFAULT 0 + #define SERCOM5_PAD2_DEFAULT PINMUX_PA24D_SERCOM5_PAD2 + #define SERCOM5_PAD3_DEFAULT PINMUX_PA25D_SERCOM5_PAD3 + +#else + /* SERCOM0 */ + #define SERCOM0_PAD0_DEFAULT PINMUX_PA04D_SERCOM0_PAD0 + #define SERCOM0_PAD1_DEFAULT PINMUX_PA05D_SERCOM0_PAD1 + #define SERCOM0_PAD2_DEFAULT PINMUX_PA06D_SERCOM0_PAD2 + #define SERCOM0_PAD3_DEFAULT PINMUX_PA07D_SERCOM0_PAD3 + + /* SERCOM1 */ +#if SAM_PART_IS_DEFINED(SAMD21G15L) || SAM_PART_IS_DEFINED(SAMD21G16L) + #define SERCOM1_PAD0_DEFAULT PINMUX_PA16C_SERCOM1_PAD0 + #define SERCOM1_PAD1_DEFAULT PINMUX_PA17C_SERCOM1_PAD1 + #define SERCOM1_PAD2_DEFAULT PINMUX_PA18C_SERCOM1_PAD2 + #define SERCOM1_PAD3_DEFAULT PINMUX_PA19C_SERCOM1_PAD3 +#else + #define SERCOM1_PAD0_DEFAULT PINMUX_PA00D_SERCOM1_PAD0 + #define SERCOM1_PAD1_DEFAULT PINMUX_PA01D_SERCOM1_PAD1 + #define SERCOM1_PAD2_DEFAULT PINMUX_PA30D_SERCOM1_PAD2 + #define SERCOM1_PAD3_DEFAULT PINMUX_PA31D_SERCOM1_PAD3 +#endif + + /* SERCOM2 */ + #define SERCOM2_PAD0_DEFAULT PINMUX_PA08D_SERCOM2_PAD0 + #define SERCOM2_PAD1_DEFAULT PINMUX_PA09D_SERCOM2_PAD1 + #define SERCOM2_PAD2_DEFAULT PINMUX_PA10D_SERCOM2_PAD2 + #define SERCOM2_PAD3_DEFAULT PINMUX_PA11D_SERCOM2_PAD3 + + /* SERCOM3 */ + #define SERCOM3_PAD0_DEFAULT PINMUX_PA16D_SERCOM3_PAD0 + #define SERCOM3_PAD1_DEFAULT PINMUX_PA17D_SERCOM3_PAD1 + #define SERCOM3_PAD2_DEFAULT PINMUX_PA18D_SERCOM3_PAD2 + #define SERCOM3_PAD3_DEFAULT PINMUX_PA19D_SERCOM3_PAD3 + + #if !(SAMD20E || SAMD21E) + /* SERCOM4 */ + #define SERCOM4_PAD0_DEFAULT PINMUX_PA12D_SERCOM4_PAD0 + #define SERCOM4_PAD1_DEFAULT PINMUX_PA13D_SERCOM4_PAD1 + #define SERCOM4_PAD2_DEFAULT PINMUX_PA14D_SERCOM4_PAD2 + #define SERCOM4_PAD3_DEFAULT PINMUX_PA15D_SERCOM4_PAD3 + + /* SERCOM5 */ + #define SERCOM5_PAD0_DEFAULT PINMUX_PA22D_SERCOM5_PAD0 + #define SERCOM5_PAD1_DEFAULT PINMUX_PA23D_SERCOM5_PAD1 + #define SERCOM5_PAD2_DEFAULT PINMUX_PA24D_SERCOM5_PAD2 + #define SERCOM5_PAD3_DEFAULT PINMUX_PA25D_SERCOM5_PAD3 + #endif + +#endif +#endif /* SERCOM_PINOUT_H_INCLUDED */ diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/spi/quick_start_dma/qs_spi_dma_use.h b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/spi/quick_start_dma/qs_spi_dma_use.h new file mode 100644 index 000000000..b22165fe3 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/spi/quick_start_dma/qs_spi_dma_use.h @@ -0,0 +1,258 @@ +/** + * \file + * + * \brief SAM D21/R21/L21/L22/DA1/C21/R30 Quick Start Guide for Using SPI driver with DMA + * + * Copyright (c) 2014-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ + +/** + * \page asfdoc_sam0_sercom_spi_dma_use_case Quick Start Guide for Using DMA with SERCOM SPI + * + * The supported board list: + * - SAM D21 Xplained Pro + * - SAM R21 Xplained Pro + * - SAM L21 Xplained Pro + * - SAM L22 Xplained Pro + * - SAM DA1 Xplained Pro + * - SAM C21 Xplained Pro + * - SAM R30 Xplained Pro + * + * This quick start will transmit a buffer data from master to slave through DMA. + * In this use case the SPI master will be configured with the following + * settings on SAM Xplained Pro: + * - Master Mode enabled + * - MSB of the data is transmitted first + * - Transfer mode 0 + * - SPI MUX Setting E + * - 8-bit character size + * - Not enabled in sleep mode + * - Baudrate 100000 + * - GLCK generator 0 + * + * The SPI slave will be configured with the following settings: + * - Slave mode enabled + * - Preloading of shift register enabled + * - MSB of the data is transmitted first + * - Transfer mode 0 + * - SPI MUX Setting E + * - 8-bit character size + * - Not enabled in sleep mode + * - GLCK generator 0 + * + * Note that the pinouts on other boards may different, see next sector for + * details. + * + * \section asfdoc_sam0_sercom_spi_dma_use_case_setup Setup + * + * \subsection asfdoc_sam0_sercom_spi_dma_use_case_prereq Prerequisites + * The following connections has to be made using wires: + * - SAM D21/DA1 Xplained Pro. + * - \b SS_0: EXT1 PIN15 (PA05) <--> EXT2 PIN15 (PA17) + * - \b DO/DI: EXT1 PIN16 (PA06) <--> EXT2 PIN17 (PA16) + * - \b DI/DO: EXT1 PIN17 (PA04) <--> EXT2 PIN16 (PA18) + * - \b SCK: EXT1 PIN18 (PA07) <--> EXT2 PIN18 (PA19) + * - SAM R21 Xplained Pro. + * - \b SS_0: EXT1 PIN15 (PB03) <--> EXT1 PIN10 (PA23) + * - \b DO/DI: EXT1 PIN16 (PB22) <--> EXT1 PIN9 (PA22) + * - \b DI/DO: EXT1 PIN17 (PB02) <--> EXT1 PIN7 (PA18) + * - \b SCK: EXT1 PIN18 (PB23) <--> EXT1 PIN8 (PA19) + * - SAM L21 Xplained Pro. + * - \b SS_0: EXT1 PIN15 (PA05) <--> EXT1 PIN12 (PA09) + * - \b DO/DI: EXT1 PIN16 (PA06) <--> EXT1 PIN11 (PA08) + * - \b DI/DO: EXT1 PIN17 (PA04) <--> EXT2 PIN03 (PA10) + * - \b SCK: EXT1 PIN18 (PA07) <--> EXT2 PIN04 (PA11) + * - SAM L22 Xplained Pro. + * - \b SS_0: EXT1 PIN15 (PB21) <--> EXT2 PIN15 (PA17) + * - \b DO/DI: EXT1 PIN16 (PB00) <--> EXT2 PIN17 (PA16) + * - \b DI/DO: EXT1 PIN17 (PB02) <--> EXT2 PIN16 (PA18) + * - \b SCK: EXT1 PIN18 (PB01) <--> EXT2 PIN18 (PA19) + * - SAM C21 Xplained Pro. + * - \b SS_0: EXT1 PIN15 (PA17) <--> EXT2 PIN15 (PB03) + * - \b DO/DI: EXT1 PIN16 (PA18) <--> EXT2 PIN17 (PB02) + * - \b DI/DO: EXT1 PIN17 (PA16) <--> EXT2 PIN16 (PB00) + * - \b SCK: EXT1 PIN18 (PA19) <--> EXT2 PIN18 (PB01) + * + * \subsection asfdoc_sam0_spi_dma_use_case_setup_code Code + * + * Add to the main application source file, before user definitions and + * functions according to your board: + * + * For SAM D21 Xplained Pro: + * \snippet samd21_xplained_pro/conf_quick_start.h definition_master + * \snippet samd21_xplained_pro/conf_quick_start.h definition_slave + * \snippet samd21_xplained_pro/conf_quick_start.h definition_peripheral_trigger + * For SAM R21 Xplained Pro: + * \snippet samr21_xplained_pro/conf_quick_start.h definition_master + * \snippet samr21_xplained_pro/conf_quick_start.h definition_slave + * \snippet samr21_xplained_pro/conf_quick_start.h definition_peripheral_trigger + * For SAM L21 Xplained Pro: + * \snippet saml21_xplained_pro/conf_quick_start.h definition_master + * \snippet saml21_xplained_pro/conf_quick_start.h definition_slave + * \snippet saml21_xplained_pro/conf_quick_start.h definition_peripheral_trigger + * For SAM L22 Xplained Pro: + * \snippet saml22_xplained_pro/conf_quick_start.h definition_master + * \snippet saml22_xplained_pro/conf_quick_start.h definition_slave + * \snippet saml22_xplained_pro/conf_quick_start.h definition_peripheral_trigger + * For SAM DA1 Xplained Pro: + * \snippet samda1_xplained_pro/conf_quick_start.h definition_master + * \snippet samda1_xplained_pro/conf_quick_start.h definition_slave + * \snippet samda1_xplained_pro/conf_quick_start.h definition_peripheral_trigger + * For SAM C21 Xplained Pro: + * \snippet samc21_xplained_pro/conf_quick_start.h definition_master + * \snippet samc21_xplained_pro/conf_quick_start.h definition_slave + * \snippet samc21_xplained_pro/conf_quick_start.h definition_peripheral_trigger + * + * Add to the main application source file, outside of any functions: + * \snippet qs_spi_dma_use.c buf_length + * \snippet qs_spi_dma_use.c spi_baudrate + * \snippet qs_spi_dma_use.c slave_select_pin + * \snippet qs_spi_dma_use.c spi_buffer + * \snippet qs_spi_dma_use.c spi_module_inst + * \snippet qs_spi_dma_use.c dma_transfer_done_flag + * \snippet qs_spi_dma_use.c slave_dev_inst + * \snippet qs_spi_dma_use.c dma_transfer_descriptor + * + * Copy-paste the following setup code to your user application: + * \snippet qs_spi_dma_use.c setup + * + * Add to user application initialization (typically the start of \c main()): + * \snippet qs_spi_dma_use.c setup_init + * + * \subsection asfdoc_sam0_spi_dma_use_case_setup_flow Workflow + * -# Create a module software instance structure for the SPI module to store + * the SPI driver state while it is in use. + * \snippet qs_spi_dma_use.c spi_module_inst + * \note This should never go out of scope as long as the module is in use. + * In most cases, this should be global. + * + * -# Create a module software instance structure for DMA resource to store + * the DMA resource state while it is in use. + * \snippet qs_spi_dma_use.c dma_resource + * \note This should never go out of scope as long as the module is in use. + * In most cases, this should be global. + * + * -# Create transfer done flag to indication DMA transfer done. + * \snippet qs_spi_dma_use.c dma_transfer_done_flag + * -# Define the buffer length for TX/RX. + * \snippet qs_spi_dma_use.c buf_length + * -# Create buffer to store the data to be transferred. + * \snippet qs_spi_dma_use.c spi_buffer + * -# Create the SPI module configuration struct, which can be filled out to + * adjust the configuration of a physical SPI peripheral. + * \snippet qs_spi_dma_use.c spi_master_config + * \snippet qs_spi_dma_use.c spi_slave_config + * -# Initialize the SPI configuration struct with the module's default values. + * \snippet qs_spi_dma_use.c spi_master_conf_defaults + * \snippet qs_spi_dma_use.c spi_slave_conf_defaults + * \note This should always be performed before using the configuration + * struct to ensure that all values are initialized to known default + * settings. + * + * -# Alter the SPI settings to configure the physical pinout, baudrate, and + * other relevant parameters. + * \snippet qs_spi_dma_use.c spi_master_mux_setting + * \snippet qs_spi_dma_use.c spi_slave_mux_setting + * -# Configure the SPI module with the desired settings, retrying while the + * driver is busy until the configuration is stressfully set. + * \snippet qs_spi_dma_use.c spi_master_init + * \snippet qs_spi_dma_use.c spi_slave_init + * -# Enable the SPI module. + * \snippet qs_spi_dma_use.c spi_master_enable + * \snippet qs_spi_dma_use.c spi_slave_enable + * + * -# Create the DMA resource configuration structure, which can be filled out to + * adjust the configuration of a single DMA transfer. + * \snippet qs_spi_dma_use.c dma_tx_setup_1 + * \snippet qs_spi_dma_use.c dma_rx_setup_1 + * + * -# Initialize the DMA resource configuration struct with the module's + * default values. + * \snippet qs_spi_dma_use.c dma_tx_setup_2 + * \snippet qs_spi_dma_use.c dma_rx_setup_2 + * \note This should always be performed before using the configuration + * struct to ensure that all values are initialized to known default + * settings. + * + * -# Set extra configurations for the DMA resource. It is using peripheral + * trigger. SERCOM TX empty and RX complete trigger causes a beat transfer in + * this example. + * \snippet qs_spi_dma_use.c dma_tx_setup_3 + * \snippet qs_spi_dma_use.c dma_rx_setup_3 + * + * -# Allocate a DMA resource with the configurations. + * \snippet qs_spi_dma_use.c dma_tx_setup_4 + * \snippet qs_spi_dma_use.c dma_rx_setup_4 + * + * -# Create a DMA transfer descriptor configuration structure, which can be + * filled out to adjust the configuration of a single DMA transfer. + * \snippet qs_spi_dma_use.c dma_tx_setup_5 + * \snippet qs_spi_dma_use.c dma_rx_setup_5 + * + * -# Initialize the DMA transfer descriptor configuration struct with the module's + * default values. + * \snippet qs_spi_dma_use.c dma_tx_setup_6 + * \snippet qs_spi_dma_use.c dma_rx_setup_6 + * \note This should always be performed before using the configuration + * struct to ensure that all values are initialized to known default + * settings. + * + * -# Set the specific parameters for a DMA transfer with transfer size, source + * address, and destination address. + * \snippet qs_spi_dma_use.c dma_tx_setup_7 + * \snippet qs_spi_dma_use.c dma_rx_setup_7 + * + * -# Create the DMA transfer descriptor. + * \snippet qs_spi_dma_use.c dma_tx_setup_8 + * \snippet qs_spi_dma_use.c dma_rx_setup_8 + * + * \section asfdoc_sam0_spi_dma_use_case_main Use Case + * + * \subsection asfdoc_sam0_spi_dma_use_case_main_code Code + * Copy-paste the following code to your user application: + * \snippet qs_spi_dma_use.c main + * + * \subsection asfdoc_sam0_spi_dma_use_case_main_flow Workflow + * -# Select the slave. + * \snippet qs_spi_dma_use.c select_slave + * + * -# Start the transfer job. + * \snippet qs_spi_dma_use.c main_1 + * + * -# Wait for transfer done. + * \snippet qs_spi_dma_use.c main_2 + * + * -# Deselect the slave. + * \snippet qs_spi_dma_use.c deselect_slave + * + * -# Enter endless loop. + * \snippet qs_spi_dma_use.c endless_loop + */ +/* + * Support and FAQ: visit Microchip Support + */ diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/spi/quick_start_master/qs_spi_master_basic.h b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/spi/quick_start_master/qs_spi_master_basic.h new file mode 100644 index 000000000..02b1e6de2 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/spi/quick_start_master/qs_spi_master_basic.h @@ -0,0 +1,126 @@ +/** + * \file + * + * \brief SAM SPI Quick Start + * + * Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ + +/** + * \page asfdoc_sam0_sercom_spi_master_basic_use Quick Start Guide for SERCOM SPI Master - Polled + * + * In this use case, the SPI on extension header 1 of the Xplained Pro board + * will be configured with the following settings: + * - Master Mode enabled + * - MSB of the data is transmitted first + * - Transfer mode 0 + * - SPI MUX Setting E (see \ref asfdoc_sam0_sercom_spi_mux_settings_master) + * - 8-bit character size + * - Not enabled in sleep mode + * - Baudrate 100000 + * - GLCK generator 0 + * + * + * \section asfdoc_sam0_sercom_spi_master_basic_use_setup Setup + * + * \subsection asfdoc_sam0_sercom_spi_master_basic_use_prereq Prerequisites + * There are no special setup requirements for this use-case. + * + * \subsection asfdoc_sam0_sercom_spi_master_basic_use_setup_code Code + * The following must be added to the user application: + * + * A sample buffer to send via SPI. + * \snippet qs_spi_master_basic.c buffer + * Number of entries in the sample buffer. + * \snippet qs_spi_master_basic.c buf_length + * GPIO pin to use as Slave Select. + * \snippet qs_spi_master_basic.c slave_select_pin + * A globally available software device instance struct to store the SPI driver + * state while it is in use. + * \snippet qs_spi_master_basic.c dev_inst + * A globally available peripheral slave software device instance struct. + * \snippet qs_spi_master_basic.c slave_dev_inst + * A function for configuring the SPI. + * \snippet qs_spi_master_basic.c configure_spi + * + * Add to user application \c main(). + * \snippet qs_spi_master_basic.c main_setup + * + * \section asfdoc_sam0_sercom_spi_master_basic_use_workflow Workflow + * -# Initialize system. + * \snippet qs_spi_master_basic.c system_init + * -# Set-up the SPI. + * \snippet qs_spi_master_basic.c run_config + * -# Create configuration struct. + * \snippet qs_spi_master_basic.c config + * -# Create peripheral slave configuration struct. + * \snippet qs_spi_master_basic.c slave_config + * -# Create peripheral slave software device instance struct. + * \snippet qs_spi_master_basic.c slave_dev_inst + * -# Get default peripheral slave configuration. + * \snippet qs_spi_master_basic.c slave_conf_defaults + * -# Set Slave Select pin. + * \snippet qs_spi_master_basic.c ss_pin + * -# Initialize peripheral slave software instance with configuration. + * \snippet qs_spi_master_basic.c slave_init + * -# Get default configuration to edit. + * \snippet qs_spi_master_basic.c conf_defaults + * -# Set MUX setting E. + * \snippet qs_spi_master_basic.c mux_setting + * -# Set pinmux for pad 0 (data in (MISO)). + * \snippet qs_spi_master_basic.c di + * -# Set pinmux for pad 1 as unused, so the pin can be used for other purposes. + * \snippet qs_spi_master_basic.c ss + * -# Set pinmux for pad 2 (data out (MOSI)). + * \snippet qs_spi_master_basic.c do + * -# Set pinmux for pad 3 (SCK). + * \snippet qs_spi_master_basic.c sck + * -# Initialize SPI module with configuration. + * \snippet qs_spi_master_basic.c init + * -# Enable SPI module. + * \snippet qs_spi_master_basic.c enable + * + * \section asfdoc_sam0_sercom_spi_master_basic_use_case Use Case + * \subsection asfdoc_sam0_sercom_spi_master_basic_use_case_code Code + * Add the following to your user application \c main(). + * \snippet qs_spi_master_basic.c main_use_case + * \subsection asfdoc_sam0_sercom_spi_master_basic_use_case_workflow Workflow + * -# Select slave. + * \snippet qs_spi_master_basic.c select_slave + * -# Write buffer to SPI slave. + * \snippet qs_spi_master_basic.c write + * -# Deselect slave. + * \snippet qs_spi_master_basic.c deselect_slave + * -# Light up. + * \snippet qs_spi_master_basic.c light_up + * -# Infinite loop. + * \snippet qs_spi_master_basic.c inf_loop + */ +/* + * Support and FAQ: visit Microchip Support + */ diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/spi/quick_start_slave/qs_spi_slave_basic.h b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/spi/quick_start_slave/qs_spi_slave_basic.h new file mode 100644 index 000000000..1cf9bb6eb --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/spi/quick_start_slave/qs_spi_slave_basic.h @@ -0,0 +1,116 @@ +/** + * \file + * + * \brief SAM SPI Quick Start + * + * Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ + +/** + * \page asfdoc_sam0_sercom_spi_slave_basic_use Quick Start Guide for SERCOM SPI Slave - Polled + * + * In this use case, the SPI on extension header 1 of the Xplained Pro board + * will configured with the following settings: + * - Slave mode enabled + * - Preloading of shift register enabled + * - MSB of the data is transmitted first + * - Transfer mode 0 + * - SPI MUX Setting E (see \ref asfdoc_sam0_sercom_spi_mux_settings_slave) + * - 8-bit character size + * - Not enabled in sleep mode + * - GLCK generator 0 + * + * + * \section asfdoc_sam0_sercom_spi_slave_basic_use_setup Setup + * + * \subsection asfdoc_sam0_sercom_spi_slave_basic_use_prereq Prerequisites + * The device must be connected to an SPI master which must read from the device. + * + * \subsection asfdoc_sam0_sercom_spi_slave_basic_use_setup_code Code + * The following must be added to the user application source file, outside + * any functions: + * + * A sample buffer to send via SPI. + * \snippet qs_spi_slave_basic.c buffer + * Number of entries in the sample buffer. + * \snippet qs_spi_slave_basic.c buf_length + * A globally available software device instance struct to store the SPI driver + * state while it is in use. + * \snippet qs_spi_slave_basic.c dev_inst + * A function for configuring the SPI. + * \snippet qs_spi_slave_basic.c configure_spi + * + * Add to user application \c main(). + * \snippet qs_spi_slave_basic.c main_start + * + * \subsection asfdoc_sam0_sercom_spi_slave_basic_use_workflow Workflow + * -# Initialize system. + * \snippet qs_spi_slave_basic.c system_init + * -# Set-up the SPI. + * \snippet qs_spi_slave_basic.c run_config + * -# Create configuration struct. + * \snippet qs_spi_slave_basic.c config + * -# Get default configuration to edit. + * \snippet qs_spi_slave_basic.c conf_defaults + * -# Set the SPI in slave mode. + * \snippet qs_spi_slave_basic.c conf_spi_slave_instance + * -# Enable preloading of shift register. + * \snippet qs_spi_slave_basic.c conf_preload + * -# Set frame format to SPI frame. + * \snippet qs_spi_slave_basic.c conf_format + * -# Set MUX setting E. + * \snippet qs_spi_slave_basic.c mux_setting + * -# Set pinmux for pad 0 (data in MOSI). + * \snippet qs_spi_slave_basic.c di + * -# Set pinmux for pad 1 (slave select). + * \snippet qs_spi_slave_basic.c ss + * -# Set pinmux for pad 2 (data out MISO). + * \snippet qs_spi_slave_basic.c do + * -# Set pinmux for pad 3 (SCK). + * \snippet qs_spi_slave_basic.c sck + * -# Initialize SPI module with configuration. + * \snippet qs_spi_slave_basic.c init + * -# Enable SPI module. + * \snippet qs_spi_slave_basic.c enable + * + * \section asfdoc_sam0_sercom_spi_slave_basic_use_case Use Case + * \subsection asfdoc_sam0_sercom_spi_slave_basic_use_case_code Code + * Add the following to your user application \c main(). + * \snippet qs_spi_slave_basic.c main_use_case + * \subsection asfdoc_sam0_sercom_spi_slave_basic_use_case_workflow Workflow + * -# Read data from SPI master. + * \snippet qs_spi_slave_basic.c read + * -# Compare the received data with the transmitted data from SPI master. + * \snippet qs_spi_slave_basic.c compare + * -# Infinite loop. If the data is matched, LED0 will flash slowly. Otherwise, + * LED will flash quickly. + * \snippet qs_spi_slave_basic.c inf_loop + */ +/* + * Support and FAQ: visit Microchip Support + */ diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/spi/spi.c b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/spi/spi.c new file mode 100644 index 000000000..4188634de --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/spi/spi.c @@ -0,0 +1,1255 @@ +/** + * \file + * + * \brief SAM Serial Peripheral Interface Driver + * + * Copyright (c) 2012-2020 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#include "spi.h" + +/** + * \brief Resets the SPI module + * + * This function will reset the SPI module to its power on default values and + * disable it. + * + * \param[in,out] module Pointer to the software instance struct + */ +void spi_reset( + struct spi_module *const module) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + SercomSpi *const spi_module = &(module->hw->SPI); + + /* Disable the module */ + spi_disable(module); + + while (spi_is_syncing(module)) { + /* Wait until the synchronization is complete */ + } + + /* Software reset the module */ + spi_module->CTRLA.reg |= SERCOM_SPI_CTRLA_SWRST; +} + +/** + * \brief Set the baudrate of the SPI module + * + * This function will set the baudrate of the SPI module. + * + * \param[in] module Pointer to the software instance struct + * \param[in] baudrate The baudrate wanted + * + * \return The status of the configuration. + * \retval STATUS_ERR_INVALID_ARG If invalid argument(s) were provided + * \retval STATUS_OK If the configuration was written + */ +enum status_code spi_set_baudrate( + struct spi_module *const module, + uint32_t baudrate) +{ + /* Sanity check arguments */ + Assert(module); + Assert(baudrate); + Assert(module->hw); + + /* Value to write to BAUD register */ + uint16_t baud = 0; + + SercomSpi *const spi_module = &(module->hw->SPI); + + /* Disable the module */ + spi_disable(module); + + while (spi_is_syncing(module)) { + /* Wait until the synchronization is complete */ + } + + /* Find frequency of the internal SERCOMi_GCLK_ID_CORE */ + uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw); + uint32_t gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; + uint32_t internal_clock = system_gclk_chan_get_hz(gclk_index); + + /* Get baud value, based on baudrate and the internal clock frequency */ + enum status_code error_code = _sercom_get_sync_baud_val( + baudrate, internal_clock, &baud); + + if (error_code != STATUS_OK) { + /* Baud rate calculation error, return status code */ + return STATUS_ERR_INVALID_ARG; + } + + spi_module->BAUD.reg = (uint8_t)baud; + + while (spi_is_syncing(module)) { + /* Wait until the synchronization is complete */ + } + + /* Enable the module */ + spi_enable(module); + + while (spi_is_syncing(module)) { + /* Wait until the synchronization is complete */ + } + + return STATUS_OK; +} + +# if CONF_SPI_SLAVE_ENABLE == true +/** + * \internal Clears the Transmit Complete interrupt flag. + * + * \param[in] module Pointer to the software instance struct + */ +static void _spi_clear_tx_complete_flag( + struct spi_module *const module) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + SercomSpi *const spi_module = &(module->hw->SPI); + + /* Clear interrupt flag */ + spi_module->INTFLAG.reg = SPI_INTERRUPT_FLAG_TX_COMPLETE; +} +# endif + +/** + * \internal Writes an SPI SERCOM configuration to the hardware module. + * + * This function will write out a given configuration to the hardware module. + * Can only be done when the module is disabled. + * + * \param[in] module Pointer to the software instance struct + * \param[in] config Pointer to the configuration struct + * + * \return The status of the configuration. + * \retval STATUS_ERR_INVALID_ARG If invalid argument(s) were provided + * \retval STATUS_OK If the configuration was written + */ +static enum status_code _spi_set_config( + struct spi_module *const module, + const struct spi_config *const config) +{ + /* Sanity check arguments */ + Assert(module); + Assert(config); + Assert(module->hw); + + SercomSpi *const spi_module = &(module->hw->SPI); + Sercom *const hw = module->hw; + + struct system_pinmux_config pin_conf; + system_pinmux_get_config_defaults(&pin_conf); + pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT; + if(config->mode == SPI_MODE_SLAVE) { + pin_conf.input_pull = SYSTEM_PINMUX_PIN_PULL_NONE; + } + + uint32_t pad_pinmuxes[] = { + config->pinmux_pad0, config->pinmux_pad1, + config->pinmux_pad2, config->pinmux_pad3 + }; + + /* Configure the SERCOM pins according to the user configuration */ + for (uint8_t pad = 0; pad < 4; pad++) { + uint32_t current_pinmux = pad_pinmuxes[pad]; + + if (current_pinmux == PINMUX_DEFAULT) { + current_pinmux = _sercom_get_default_pad(hw, pad); + } + + if (current_pinmux != PINMUX_UNUSED) { + pin_conf.mux_position = current_pinmux & 0xFFFF; + system_pinmux_pin_set_config(current_pinmux >> 16, &pin_conf); + } + } + + module->mode = config->mode; + module->character_size = config->character_size; + module->receiver_enabled = config->receiver_enable; +# ifdef FEATURE_SPI_HARDWARE_SLAVE_SELECT + module->master_slave_select_enable = config->master_slave_select_enable; +# endif + +# if CONF_SPI_MASTER_ENABLE == true + /* Value to write to BAUD register */ + uint16_t baud = 0; +# endif + /* Value to write to CTRLA register */ + uint32_t ctrla = 0; + /* Value to write to CTRLB register */ + uint32_t ctrlb = 0; + +# if CONF_SPI_MASTER_ENABLE == true + /* Find baud value and write it */ + if (config->mode == SPI_MODE_MASTER) { + /* Find frequency of the internal SERCOMi_GCLK_ID_CORE */ + uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw); + uint32_t gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; + uint32_t internal_clock = system_gclk_chan_get_hz(gclk_index); + + /* Get baud value, based on baudrate and the internal clock frequency */ + enum status_code error_code = _sercom_get_sync_baud_val( + config->mode_specific.master.baudrate, + internal_clock, &baud); + + if (error_code != STATUS_OK) { + /* Baud rate calculation error, return status code */ + return STATUS_ERR_INVALID_ARG; + } + + spi_module->BAUD.reg = (uint8_t)baud; + } +# endif +# if CONF_SPI_SLAVE_ENABLE == true + if (config->mode == SPI_MODE_SLAVE) { + /* Set frame format */ + ctrla = config->mode_specific.slave.frame_format; + + /* Set address mode */ + ctrlb = config->mode_specific.slave.address_mode; + + /* Set address and address mask*/ + spi_module->ADDR.reg |= + (config->mode_specific.slave.address << SERCOM_SPI_ADDR_ADDR_Pos) | + (config->mode_specific.slave.address_mask << SERCOM_SPI_ADDR_ADDRMASK_Pos); + + if (config->mode_specific.slave.preload_enable) { + /* Enable pre-loading of shift register */ + ctrlb |= SERCOM_SPI_CTRLB_PLOADEN; + } + } +# endif + /* Set data order */ + ctrla |= config->data_order; + + /* Set clock polarity and clock phase */ + ctrla |= config->transfer_mode; + + /* Set MUX setting */ + ctrla |= config->mux_setting; + + /* Set SPI character size */ + ctrlb |= config->character_size; + + /* Set whether module should run in standby. */ + if (config->run_in_standby || system_is_debugger_present()) { + ctrla |= SERCOM_SPI_CTRLA_RUNSTDBY; + } + + if (config->receiver_enable) { + /* Enable receiver */ + ctrlb |= SERCOM_SPI_CTRLB_RXEN; + } +# ifdef FEATURE_SPI_SLAVE_SELECT_LOW_DETECT + if (config->select_slave_low_detect_enable) { + /* Enable Slave Select Low Detect */ + ctrlb |= SERCOM_SPI_CTRLB_SSDE; + } +# endif +# ifdef FEATURE_SPI_HARDWARE_SLAVE_SELECT + if (config->master_slave_select_enable) { + /* Enable Master Slave Select */ + ctrlb |= SERCOM_SPI_CTRLB_MSSEN; + } +# endif + /* Write CTRLA register */ + spi_module->CTRLA.reg |= ctrla; + + /* Write CTRLB register */ + spi_module->CTRLB.reg |= ctrlb; + + return STATUS_OK; +} + +#if SPI_CALLBACK_MODE == false +/** + * \internal Checks an SPI config against current set config + * + * This function will check that the config does not alter the + * configuration of the module. If the new config changes any + * setting, the initialization will be discarded. + * + * \param[in] module Pointer to the software instance struct + * \param[in] config Pointer to the configuration struct + * + * \return The status of the configuration. + * \retval STATUS_ERR_INVALID_ARG If invalid argument(s) were provided + * \retval STATUS_ERR_DENIED If configuration was different from previous + * \retval STATUS_OK If the configuration was written + */ +static enum status_code _spi_check_config( + struct spi_module *const module, + const struct spi_config *const config) +{ + /* Sanity check arguments */ + Assert(module); + Assert(config); + Assert(module->hw); + + SercomSpi *const spi_module = &(module->hw->SPI); + Sercom *const hw = module->hw; + + uint32_t pad_pinmuxes[] = { + config->pinmux_pad0, config->pinmux_pad1, + config->pinmux_pad2, config->pinmux_pad3 + }; + + /* Compare the current SERCOM pins against the user configuration */ + for (uint8_t pad = 0; pad < 4; pad++) { + uint32_t current_pinmux = pad_pinmuxes[pad]; + + if (current_pinmux == PINMUX_DEFAULT) { + current_pinmux = _sercom_get_default_pad(hw, pad); + } + + if (current_pinmux == PINMUX_UNUSED) { + continue; + } + + if ((current_pinmux & 0xFFFF) != + system_pinmux_pin_get_mux_position(current_pinmux >> 16)) { + module->hw = NULL; + return STATUS_ERR_DENIED; + } + } + +# if CONF_SPI_MASTER_ENABLE == true + /* Value to read BAUD register */ + uint16_t baud; + uint32_t external_clock = system_gclk_chan_get_hz(SERCOM_GCLK_ID); +# endif + /* Value to read CTRLA, CTRLB and ADDR register */ + uint32_t ctrla = 0; + uint32_t ctrlb = 0; +# if CONF_SPI_SLAVE_ENABLE == true + uint32_t addr = 0; +# endif + +# if CONF_SPI_MASTER_ENABLE == true + /* Find baud value and compare it */ + if (config->mode == SPI_MODE_MASTER) { + enum status_code error_code = _sercom_get_sync_baud_val( + config->mode_specific.master.baudrate, + external_clock, &baud); + + if (error_code != STATUS_OK) { + /* Baud rate calculation error, return status code */ + return STATUS_ERR_INVALID_ARG; + } + + if (spi_module->BAUD.reg != (uint8_t)baud) { + return STATUS_ERR_DENIED; + } + + ctrla |= SERCOM_SPI_CTRLA_MODE(0x3); + } +# endif + +# if CONF_SPI_SLAVE_ENABLE == true + if (config->mode == SPI_MODE_SLAVE) { + + /* Set frame format */ + ctrla |= config->mode_specific.slave.frame_format; + + /* Set address mode */ + ctrlb |= config->mode_specific.slave.address_mode; + + /* Set address and address mask*/ + addr |= (config->mode_specific.slave.address << SERCOM_SPI_ADDR_ADDR_Pos) | + (config->mode_specific.slave.address_mask << SERCOM_SPI_ADDR_ADDRMASK_Pos); + if (spi_module->CTRLA.reg != addr) { + return STATUS_ERR_DENIED; + } + + if (config->mode_specific.slave.preload_enable) { + /* Enable pre-loading of shift register */ + ctrlb |= SERCOM_SPI_CTRLB_PLOADEN; + } + ctrla |= SERCOM_SPI_CTRLA_MODE(0x2); + } +# endif + /* Set data order */ + ctrla |= config->data_order; + + /* Set clock polarity and clock phase */ + ctrla |= config->transfer_mode; + + /* Set MUX setting */ + ctrla |= config->mux_setting; + + /* Set SPI character size */ + ctrlb |= config->character_size; + + if (config->run_in_standby) { + /* Enable in sleep mode */ + ctrla |= SERCOM_SPI_CTRLA_RUNSTDBY; + } + + if (config->receiver_enable) { + /* Enable receiver */ + ctrlb |= SERCOM_SPI_CTRLB_RXEN; + } + +# ifdef FEATURE_SPI_SLAVE_SELECT_LOW_DETECT + if (config->select_slave_low_detect_enable) { + /* Enable Slave Select Low Detect */ + ctrlb |= SERCOM_SPI_CTRLB_SSDE; + } +# endif +# ifdef FEATURE_SPI_HARDWARE_SLAVE_SELECT + if (config->master_slave_select_enable) { + /* Enable Master Slave Select */ + ctrlb |= SERCOM_SPI_CTRLB_MSSEN; + } +# endif + + ctrla |= SERCOM_SPI_CTRLA_ENABLE; + + /* Check that same config is set */ + if (spi_module->CTRLA.reg == ctrla && + spi_module->CTRLB.reg == ctrlb) { + module->mode = config->mode; + module->character_size = config->character_size; + return STATUS_OK; + } + + /* Not same config, wipe module pointer and return */ + module->hw = NULL; + + return STATUS_ERR_DENIED; +} +#endif + +/** + * \brief Initializes the SERCOM SPI module + * + * This function will initialize the SERCOM SPI module, based on the values + * of the config struct. + * + * \param[out] module Pointer to the software instance struct + * \param[in] hw Pointer to hardware instance + * \param[in] config Pointer to the config struct + * + * \return Status of the initialization. + * \retval STATUS_OK Module initiated correctly + * \retval STATUS_ERR_DENIED If module is enabled + * \retval STATUS_BUSY If module is busy resetting + * \retval STATUS_ERR_INVALID_ARG If invalid argument(s) were provided + */ +enum status_code spi_init( + struct spi_module *const module, + Sercom *const hw, + const struct spi_config *const config) +{ + + /* Sanity check arguments */ + Assert(module); + Assert(hw); + Assert(config); + + /* Initialize device instance */ + module->hw = hw; + + SercomSpi *const spi_module = &(module->hw->SPI); + + /* Check if module is enabled. */ + if (spi_module->CTRLA.reg & SERCOM_SPI_CTRLA_ENABLE) { +# if SPI_CALLBACK_MODE == false + /* Check if config is valid */ + return _spi_check_config(module, config); +# else + return STATUS_ERR_DENIED; +# endif + } + + /* Check if reset is in progress. */ + if (spi_module->CTRLA.reg & SERCOM_SPI_CTRLA_SWRST){ + return STATUS_BUSY; + } + + uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw); + uint32_t pm_index, gclk_index; +#if (SAML21) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + if (sercom_index == 5) { +# ifdef ID_SERCOM5 + pm_index = MCLK_APBDMASK_SERCOM5_Pos; + gclk_index = SERCOM5_GCLK_ID_CORE; +# else + return STATUS_ERR_INVALID_ARG; +# endif + } else { + pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos; + gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; + } +#elif (SAMC21) + if (sercom_index == 5) { +# ifdef ID_SERCOM5 + pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos; + gclk_index = SERCOM5_GCLK_ID_CORE; +# else + return STATUS_ERR_INVALID_ARG; +# endif + } else { + pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos; + gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; + } +#elif (SAMC20) || (SAML22) + pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos; + gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; +#else + pm_index = sercom_index + PM_APBCMASK_SERCOM0_Pos; + gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; +#endif + + /* Turn on module in PM */ +#if (SAML21) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + if (sercom_index == 5) { +# ifdef ID_SERCOM5 + system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBD, 1 << pm_index); +# else + return STATUS_ERR_INVALID_ARG; +# endif + } else { + system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index); + } +#else + system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index); +#endif + + /* Set up the GCLK for the module */ + struct system_gclk_chan_config gclk_chan_conf; + system_gclk_chan_get_config_defaults(&gclk_chan_conf); + gclk_chan_conf.source_generator = config->generator_source; + system_gclk_chan_set_config(gclk_index, &gclk_chan_conf); + system_gclk_chan_enable(gclk_index); + sercom_set_gclk_generator(config->generator_source, false); + +# if CONF_SPI_MASTER_ENABLE == true + if (config->mode == SPI_MODE_MASTER) { + /* Set the SERCOM in SPI master mode */ + spi_module->CTRLA.reg |= SERCOM_SPI_CTRLA_MODE(0x3); + } +# endif + +# if CONF_SPI_SLAVE_ENABLE == true + if (config->mode == SPI_MODE_SLAVE) { + /* Set the SERCOM in SPI slave mode */ + spi_module->CTRLA.reg |= SERCOM_SPI_CTRLA_MODE(0x2); + } +# endif + +#if SPI_CALLBACK_MODE == true + /* Temporary variables */ + uint8_t i; + uint8_t instance_index; + + /* Initialize parameters */ + for (i = 0; i < SPI_CALLBACK_N; i++) { + module->callback[i] = NULL; + } + module->tx_buffer_ptr = NULL; + module->rx_buffer_ptr = NULL; + module->remaining_tx_buffer_length = 0x0000; + module->remaining_rx_buffer_length = 0x0000; + module->registered_callback = 0x00; + module->enabled_callback = 0x00; + module->status = STATUS_OK; + module->dir = SPI_DIRECTION_IDLE; + module->locked = false; + /* + * Set interrupt handler and register SPI software module struct in + * look-up table + */ + instance_index = _sercom_get_sercom_inst_index(module->hw); + _sercom_set_handler(instance_index, _spi_interrupt_handler); + _sercom_instances[instance_index] = module; +#endif + + /* Write configuration to module and return status code */ + return _spi_set_config(module, config); +} + +/** + * \brief Reads buffer of \c length SPI characters + * + * This function will read a buffer of data from an SPI peripheral by sending + * dummy SPI character if in master mode, or by waiting for data in slave mode. + * + * \note If address matching is enabled for the slave, the first character + * received and placed in the buffer will be the address. + * + * \param[in] module Pointer to the software instance struct + * \param[out] rx_data Data buffer for received data + * \param[in] length Length of data to receive + * \param[in] dummy 8- or 9-bit dummy byte to shift out in master mode + * + * \return Status of the read operation. + * \retval STATUS_OK If the read was completed + * \retval STATUS_ABORTED If transaction was ended by master before + * the entire buffer was transferred + * \retval STATUS_ERR_INVALID_ARG If invalid argument(s) were provided + * \retval STATUS_ERR_TIMEOUT If the operation was not completed within the + * timeout in slave mode + * \retval STATUS_ERR_DENIED If the receiver is not enabled + * \retval STATUS_ERR_OVERFLOW If the data is overflown + */ +enum status_code spi_read_buffer_wait( + struct spi_module *const module, + uint8_t *rx_data, + uint16_t length, + uint16_t dummy) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + +# if SPI_CALLBACK_MODE == true + if (module->status == STATUS_BUSY) { + /* Check if the SPI module is busy with a job */ + return STATUS_BUSY; + } +# endif + + /* Sanity check arguments */ + if (length == 0) { + return STATUS_ERR_INVALID_ARG; + } + + if (!(module->receiver_enabled)) { + return STATUS_ERR_DENIED; + } +# if CONF_SPI_SLAVE_ENABLE == true + if ((module->mode == SPI_MODE_SLAVE) && (spi_is_write_complete(module))) { + /* Clear TX complete flag */ + _spi_clear_tx_complete_flag(module); + } +# endif + uint16_t rx_pos = 0; + + while (length--) { +# if CONF_SPI_MASTER_ENABLE == true + if (module->mode == SPI_MODE_MASTER) { + /* Wait until the module is ready to write a character */ + while (!spi_is_ready_to_write(module)) { + } + + /* Send dummy SPI character to read in master mode */ + spi_write(module, dummy); + } +# endif + +# if CONF_SPI_SLAVE_ENABLE == true + /* Start timeout period for slave */ + if (module->mode == SPI_MODE_SLAVE) { + for (uint32_t i = 0; i <= SPI_TIMEOUT; i++) { + if (spi_is_ready_to_read(module)) { + break; + } + } + /* Check if master has ended the transaction */ + if (spi_is_write_complete(module)) { + _spi_clear_tx_complete_flag(module); + return STATUS_ABORTED; + } + + if (!spi_is_ready_to_read(module)) { + /* Not ready to read data within timeout period */ + return STATUS_ERR_TIMEOUT; + } + } +# endif + + /* Wait until the module is ready to read a character */ + while (!spi_is_ready_to_read(module)) { + } + + uint16_t received_data = 0; + enum status_code retval = spi_read(module, &received_data); + + if (retval != STATUS_OK) { + /* Overflow, abort */ + return retval; + } + + /* Read value will be at least 8-bits long */ + rx_data[rx_pos++] = received_data; + + /* If 9-bit data, write next received byte to the buffer */ + if (module->character_size == SPI_CHARACTER_SIZE_9BIT) { + rx_data[rx_pos++] = (received_data >> 8); + } + } + + return STATUS_OK; +} + +/** + * \brief Sends and reads a single SPI character + * + * This function will transfer a single SPI character via SPI and return the + * SPI character that is shifted into the shift register. + * + * In master mode the SPI character will be sent immediately and the received + * SPI character will be read as soon as the shifting of the data is + * complete. + * + * In slave mode this function will place the data to be sent into the transmit + * buffer. It will then block until an SPI master has shifted a complete + * SPI character, and the received data is available. + * + * \note The data to be sent might not be sent before the next transfer, as + * loading of the shift register is dependent on SCK. + * \note If address matching is enabled for the slave, the first character + * received and placed in the buffer will be the address. + * + * \param[in] module Pointer to the software instance struct + * \param[in] tx_data SPI character to transmit + * \param[out] rx_data Pointer to store the received SPI character + * + * \return Status of the operation. + * \retval STATUS_OK If the operation was completed + * \retval STATUS_ERR_TIMEOUT If the operation was not completed within the + * timeout in slave mode + * \retval STATUS_ERR_DENIED If the receiver is not enabled + * \retval STATUS_ERR_OVERFLOW If the incoming data is overflown + */ +enum status_code spi_transceive_wait( + struct spi_module *const module, + uint16_t tx_data, + uint16_t *rx_data) +{ + /* Sanity check arguments */ + Assert(module); + + if (!(module->receiver_enabled)) { + return STATUS_ERR_DENIED; + } + +# if SPI_CALLBACK_MODE == true + if (module->status == STATUS_BUSY) { + /* Check if the SPI module is busy with a job */ + return STATUS_BUSY; + } +# endif + +# if CONF_SPI_SLAVE_ENABLE == true + uint16_t j; +# endif + enum status_code retval = STATUS_OK; + +# if CONF_SPI_SLAVE_ENABLE == true + /* Start timeout period for slave */ + if (module->mode == SPI_MODE_SLAVE) { + for (j = 0; j <= SPI_TIMEOUT; j++) { + if (spi_is_ready_to_write(module)) { + break; + } else if (j == SPI_TIMEOUT) { + /* Not ready to write data within timeout period */ + return STATUS_ERR_TIMEOUT; + } + } + } +# endif + /* Wait until the module is ready to write the character */ + while (!spi_is_ready_to_write(module)) { + } + + /* Write data */ + spi_write(module, tx_data); + +# if CONF_SPI_SLAVE_ENABLE == true + /* Start timeout period for slave */ + if (module->mode == SPI_MODE_SLAVE) { + for (j = 0; j <= SPI_TIMEOUT; j++) { + if (spi_is_ready_to_read(module)) { + break; + } else if (j == SPI_TIMEOUT) { + /* Not ready to read data within timeout period */ + return STATUS_ERR_TIMEOUT; + } + } + } +# endif + + /* Wait until the module is ready to read the character */ + while (!spi_is_ready_to_read(module)) { + } + + /* Read data */ + retval = spi_read(module, rx_data); + + return retval; +} + + /** + * \brief Selects slave device + * + * This function will drive the slave select pin of the selected device low or + * high depending on the select Boolean. + * If slave address recognition is enabled, the address will be sent to the + * slave when selecting it. + * + * \param[in] module Pointer to the software module struct + * \param[in] slave Pointer to the attached slave + * \param[in] select Boolean stating if the slave should be selected or + * deselected + * + * \return Status of the operation. + * \retval STATUS_OK If the slave device was selected + * \retval STATUS_ERR_UNSUPPORTED_DEV If the SPI module is operating in slave + * mode + * \retval STATUS_BUSY If the SPI module is not ready to write + * the slave address + */ +enum status_code spi_select_slave( + struct spi_module *const module, + struct spi_slave_inst *const slave, + const bool select) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + Assert(slave); + + /* Check that the SPI module is operating in master mode */ + if (module->mode != SPI_MODE_MASTER) { + return STATUS_ERR_UNSUPPORTED_DEV; + } +# ifdef FEATURE_SPI_HARDWARE_SLAVE_SELECT + if(!(module->master_slave_select_enable)) +# endif + { + if (select) { + /* Check if address recognition is enabled */ + if (slave->address_enabled) { + /* Check if the module is ready to write the address */ + if (!spi_is_ready_to_write(module)) { + /* Not ready, do not select slave and return */ + port_pin_set_output_level(slave->ss_pin, true); + return STATUS_BUSY; + } + + /* Drive Slave Select low */ + port_pin_set_output_level(slave->ss_pin, false); + + /* Write address to slave */ + spi_write(module, slave->address); + + if (!(module->receiver_enabled)) { + /* Flush contents of shift register shifted back from slave */ + while (!spi_is_ready_to_read(module)) { + } + uint16_t flush = 0; + spi_read(module, &flush); + } + } else { + /* Drive Slave Select low */ + port_pin_set_output_level(slave->ss_pin, false); + } + } else { + /* Drive Slave Select high */ + port_pin_set_output_level(slave->ss_pin, true); + } + } + return STATUS_OK; +} + +/** + * \brief Sends a buffer of \c length SPI characters + * + * This function will send a buffer of SPI characters via the SPI + * and discard any data that is received. To both send and receive a buffer of + * data, use the \ref spi_transceive_buffer_wait function. + * + * Note that this function does not handle the _SS (slave select) pin(s) in + * master mode; this must be handled by the user application. + * + * \param[in] module Pointer to the software instance struct + * \param[in] tx_data Pointer to the buffer to transmit + * \param[in] length Number of SPI characters to transfer + * + * \return Status of the write operation. + * \retval STATUS_OK If the write was completed + * \retval STATUS_ABORTED If transaction was ended by master before + * entire buffer was transferred + * \retval STATUS_ERR_INVALID_ARG If invalid argument(s) were provided + * \retval STATUS_ERR_TIMEOUT If the operation was not completed within the + * timeout in slave mode + */ +enum status_code spi_write_buffer_wait( + struct spi_module *const module, + const uint8_t *tx_data, + uint16_t length) +{ + /* Sanity check arguments */ + Assert(module); + +# if SPI_CALLBACK_MODE == true + if (module->status == STATUS_BUSY) { + /* Check if the SPI module is busy with a job */ + return STATUS_BUSY; + } +# endif + + if (length == 0) { + return STATUS_ERR_INVALID_ARG; + } + +# if CONF_SPI_SLAVE_ENABLE == true + if ((module->mode == SPI_MODE_SLAVE) && (spi_is_write_complete(module))) { + /* Clear TX complete flag */ + _spi_clear_tx_complete_flag(module); + } +# endif + + uint16_t tx_pos = 0; + uint16_t flush_length = length; + + /* Write block */ + while (length--) { +# if CONF_SPI_SLAVE_ENABLE == true + /* Start timeout period for slave */ + if (module->mode == SPI_MODE_SLAVE) { + for (uint32_t i = 0; i <= SPI_TIMEOUT; i++) { + if (spi_is_ready_to_write(module)) { + break; + } + } + /* Check if master has ended the transaction */ + if (spi_is_write_complete(module)) { + _spi_clear_tx_complete_flag(module); + return STATUS_ABORTED; + } + + if (!spi_is_ready_to_write(module)) { + /* Not ready to write data within timeout period */ + return STATUS_ERR_TIMEOUT; + } + } +# endif + + /* Wait until the module is ready to write a character */ + while (!spi_is_ready_to_write(module)) { + } + + /* Write value will be at least 8-bits long */ + uint16_t data_to_send = tx_data[tx_pos++]; + + /* If 9-bit data, get next byte to send from the buffer */ + if (module->character_size == SPI_CHARACTER_SIZE_9BIT) { + data_to_send |= (tx_data[tx_pos++] << 8); + } + + /* Write the data to send */ + spi_write(module, data_to_send); + + if (module->receiver_enabled) { +# if CONF_SPI_SLAVE_ENABLE == true + /* Start timeout period for slave */ + if (module->mode == SPI_MODE_SLAVE) { + for (uint32_t i = 0; i <= SPI_TIMEOUT; i++) { + if (length && spi_is_ready_to_write(module)) { + data_to_send = tx_data[tx_pos++]; + /* If 9-bit data, get next byte to send from the buffer */ + if (module->character_size == SPI_CHARACTER_SIZE_9BIT) { + data_to_send |= (tx_data[tx_pos++] << 8); + } + + /* Write the data to send */ + spi_write(module, data_to_send); + length--; + } + if (spi_is_ready_to_read(module)) { + break; + } + } + + /* Check if master has ended the transaction */ + if (spi_is_write_complete(module)) { + _spi_clear_tx_complete_flag(module); + return STATUS_ABORTED; + } + + if (!spi_is_ready_to_read(module)) { + /* Not ready to read data within timeout period */ + return STATUS_ERR_TIMEOUT; + } + } +# endif + + while (!spi_is_ready_to_read(module)) { + } + + /* Flush read buffer */ + uint16_t flush; + spi_read(module, &flush); + flush_length--; + } + } + +# if CONF_SPI_MASTER_ENABLE == true + if (module->mode == SPI_MODE_MASTER) { + /* Wait for last byte to be transferred */ + while (!spi_is_write_complete(module)) { + } + } +# endif + +# if CONF_SPI_SLAVE_ENABLE == true + if (module->mode == SPI_MODE_SLAVE) { + if (module->receiver_enabled) { + while (flush_length) { + /* Start timeout period for slave */ + for (uint32_t i = 0; i <= SPI_TIMEOUT; i++) { + if (spi_is_ready_to_read(module)) { + break; + } + } + if (!spi_is_ready_to_read(module)) { + /* Not ready to read data within timeout period */ + return STATUS_ERR_TIMEOUT; + } + /* Flush read buffer */ + uint16_t flush; + spi_read(module, &flush); + flush_length--; + } + } + } +# endif + return STATUS_OK; +} + +/** + * \brief Sends and receives a buffer of \c length SPI characters + * + * This function will send and receive a buffer of data via the SPI. + * + * In master mode the SPI characters will be sent immediately and the + * received SPI character will be read as soon as the shifting of the SPI + * character is complete. + * + * In slave mode this function will place the data to be sent into the transmit + * buffer. It will then block until an SPI master has shifted the complete + * buffer and the received data is available. + * + * \param[in] module Pointer to the software instance struct + * \param[in] tx_data Pointer to the buffer to transmit + * \param[out] rx_data Pointer to the buffer where received data will be stored + * \param[in] length Number of SPI characters to transfer + * + * \return Status of the operation. + * \retval STATUS_OK If the operation was completed + * \retval STATUS_ERR_INVALID_ARG If invalid argument(s) were provided + * \retval STATUS_ERR_TIMEOUT If the operation was not completed within the + * timeout in slave mode + * \retval STATUS_ERR_DENIED If the receiver is not enabled + * \retval STATUS_ERR_OVERFLOW If the data is overflown + */ +enum status_code spi_transceive_buffer_wait( + struct spi_module *const module, + uint8_t *tx_data, + uint8_t *rx_data, + uint16_t length) +{ + /* Sanity check arguments */ + Assert(module); + +# if SPI_CALLBACK_MODE == true + if (module->status == STATUS_BUSY) { + /* Check if the SPI module is busy with a job */ + return STATUS_BUSY; + } +# endif + + /* Sanity check arguments */ + if (length == 0) { + return STATUS_ERR_INVALID_ARG; + } + + if (!(module->receiver_enabled)) { + return STATUS_ERR_DENIED; + } + +# if CONF_SPI_SLAVE_ENABLE == true + if ((module->mode == SPI_MODE_SLAVE) && (spi_is_write_complete(module))) { + /* Clear TX complete flag */ + _spi_clear_tx_complete_flag(module); + } +# endif + + uint16_t tx_pos = 0; + uint16_t rx_pos = 0; + uint16_t rx_length = length; + + /* Send and receive buffer */ + while (length--) { +# if CONF_SPI_SLAVE_ENABLE == true + /* Start timeout period for slave */ + if (module->mode == SPI_MODE_SLAVE) { + for (uint32_t i = 0; i <= SPI_TIMEOUT; i++) { + if (spi_is_ready_to_write(module)) { + break; + } + } + /* Check if master has ended the transaction */ + if (spi_is_write_complete(module)) { + _spi_clear_tx_complete_flag(module); + return STATUS_ABORTED; + } + + if (!spi_is_ready_to_write(module)) { + /* Not ready to write data within timeout period */ + return STATUS_ERR_TIMEOUT; + } + } +# endif + + /* Wait until the module is ready to write a character */ + while (!spi_is_ready_to_write(module)) { + } + + /* Write value will be at least 8-bits long */ + uint16_t data_to_send = tx_data[tx_pos++]; + + /* If 9-bit data, get next byte to send from the buffer */ + if (module->character_size == SPI_CHARACTER_SIZE_9BIT) { + data_to_send |= (tx_data[tx_pos++] << 8); + } + + /* Write the data to send */ + spi_write(module, data_to_send); + +# if CONF_SPI_SLAVE_ENABLE == true + /* Start timeout period for slave */ + if (module->mode == SPI_MODE_SLAVE) { + for (uint32_t i = 0; i <= SPI_TIMEOUT; i++) { + if (spi_is_ready_to_write(module)) { + data_to_send = tx_data[tx_pos++]; + /* If 9-bit data, get next byte to send from the buffer */ + if (module->character_size == SPI_CHARACTER_SIZE_9BIT) { + data_to_send |= (tx_data[tx_pos++] << 8); + } + + /* Write the data to send */ + spi_write(module, data_to_send); + length--; + } + if (spi_is_ready_to_read(module)) { + break; + } + } + /* Check if master has ended the transaction */ + if (spi_is_write_complete(module)) { + _spi_clear_tx_complete_flag(module); + return STATUS_ABORTED; + } + + if (!spi_is_ready_to_read(module)) { + /* Not ready to read data within timeout period */ + return STATUS_ERR_TIMEOUT; + } + } +# endif + + /* Wait until the module is ready to read a character */ + while (!spi_is_ready_to_read(module)) { + } + + enum status_code retval; + uint16_t received_data = 0; + rx_length--; + + retval = spi_read(module, &received_data); + + if (retval != STATUS_OK) { + /* Overflow, abort */ + return retval; + } + + /* Read value will be at least 8-bits long */ + rx_data[rx_pos++] = received_data; + + /* If 9-bit data, write next received byte to the buffer */ + if (module->character_size == SPI_CHARACTER_SIZE_9BIT) { + rx_data[rx_pos++] = (received_data >> 8); + } + } + +# if CONF_SPI_MASTER_ENABLE == true + if (module->mode == SPI_MODE_MASTER) { + /* Wait for last byte to be transferred */ + while (!spi_is_write_complete(module)) { + } + } +# endif + +# if CONF_SPI_SLAVE_ENABLE == true + if (module->mode == SPI_MODE_SLAVE) { + while (rx_length) { + /* Start timeout period for slave */ + for (uint32_t i = 0; i <= SPI_TIMEOUT; i++) { + if (spi_is_ready_to_read(module)) { + break; + } + } + if (!spi_is_ready_to_read(module)) { + /* Not ready to read data within timeout period */ + return STATUS_ERR_TIMEOUT; + } + enum status_code retval; + uint16_t received_data = 0; + rx_length--; + + retval = spi_read(module, &received_data); + + if (retval != STATUS_OK) { + /* Overflow, abort */ + return retval; + } + /* Read value will be at least 8-bits long */ + rx_data[rx_pos++] = received_data; + + /* If 9-bit data, write next received byte to the buffer */ + if (module->character_size == SPI_CHARACTER_SIZE_9BIT) { + rx_data[rx_pos++] = (received_data >> 8); + } + } + } +# endif + return STATUS_OK; +} diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/spi/spi.h b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/spi/spi.h new file mode 100644 index 000000000..8176f1eb4 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/spi/spi.h @@ -0,0 +1,1800 @@ +/** + * \file + * + * \brief SAM Serial Peripheral Interface Driver + * + * Copyright (c) 2012-2020 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#ifndef SPI_H_INCLUDED +#define SPI_H_INCLUDED + +/** + * \defgroup asfdoc_sam0_sercom_spi_group SAM Serial Peripheral Interface (SERCOM SPI) Driver + * + * This driver for Atmel® | SMART ARM®-based microcontrollers provides + * an interface for the configuration and management of the SERCOM module in + * its SPI mode to transfer SPI data frames. The following driver API modes + * are covered by this manual: + * + * - Polled APIs + * \if SPI_CALLBACK_MODE + * - Callback APIs + * \endif + * + * The following peripheral is used by this module: + * - SERCOM (Serial Communication Interface) + * + * The following devices can use this module: + * - Atmel | SMART SAM D20/D21 + * - Atmel | SMART SAM R21 + * - Atmel | SMART SAM D09/D10/D11 + * - Atmel | SMART SAM L21/L22 + * - Atmel | SMART SAM DA1 + * - Atmel | SMART SAM C20/C21 + * - Atmel | SMART SAM HA1 + * - Atmel | SMART SAM R30 + * - Atmel | SMART SAM R34 + * - Atmel | SMART SAM R35 + * + * The outline of this documentation is as follows: + * - \ref asfdoc_sam0_sercom_spi_prerequisites + * - \ref asfdoc_sam0_sercom_spi_module_overview + * - \ref asfdoc_sam0_sercom_spi_special_considerations + * - \ref asfdoc_sam0_sercom_spi_extra_info + * - \ref asfdoc_sam0_sercom_spi_examples + * - \ref asfdoc_sam0_sercom_spi_api_overview + * + * \section asfdoc_sam0_sercom_spi_prerequisites Prerequisites + * There are no prerequisites. + * + * + * \section asfdoc_sam0_sercom_spi_module_overview Module Overview + * The Serial Peripheral Interface (SPI) is a high-speed synchronous data + * transfer interface using three or four pins. It allows fast communication + * between a master device and one or more peripheral devices. + * + * A device connected to the bus must act as a master or a slave. The master + * initiates and controls all data transactions. + * The SPI master initiates a communication cycle by pulling low the Slave + * Select (SS) pin of the desired slave. The Slave Select pin is active low. + * Master and slave prepare data to be sent in their respective shift + * registers, and the master generates the required clock pulses on the SCK + * line to interchange data. Data is always shifted from master to slave on + * the Master Out - Slave In (MOSI) line, and from slave to master on the + * Master In - Slave Out (MISO) line. After each data transfer, the master can + * synchronize to the slave by pulling the SS line high. + * + * \subsection asfdoc_sam0_sercom_spi_module_features Driver Feature Macro Definition + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Driver feature macroSupported devices
FEATURE_SPI_SLAVE_SELECT_LOW_DETECTSAM D21/R21/D10/D11/L21/L22/DA1/C20/C21/R30/R34/R35
FEATURE_SPI_HARDWARE_SLAVE_SELECTSAM D21/R21/D10/D11/L21/L22/DA1/C20/C21/R30/R34/R35
FEATURE_SPI_ERROR_INTERRUPTSAM D21/R21/D10/D11/L21/L22/DA1/C20/C21/R30/R34/R35
FEATURE_SPI_SYNC_SCHEME_VERSION_2SAM D21/R21/D10/D11/L21/L22/DA1/C20/C21/R30/R34/R35
+ * \note The specific features are only available in the driver when the + * selected device supports those features. + * + * \subsection asfdoc_sam0_sercom_spi_bus SPI Bus Connection + * In \ref asfdoc_sam0_spi_connection_example "the figure below", the + * connection between one master and one slave is shown. + * + * \anchor asfdoc_sam0_spi_connection_example + * \dot + * digraph spi_slaves_par { + * subgraph cluster_spi_master { + * shift_reg [label="Shift register", shape=box]; + * mosi_m [label="MOSI", shape=none]; + * miso_m [label="MISO", shape=none]; + * sck_m [label="SCK", shape=none]; + * ss_m [label="GPIO pin", shape=none]; + * {rank=same; mosi_m miso_m sck_m ss_m} + * label="SPI Master"; + * } + * subgraph cluster_spi_slave { + * mosi_s [label="MOSI", shape=none]; + * miso_s [label="MISO", shape=none]; + * sck_s [label="SCK", shape=none]; + * ss_s [label="SS", shape=none]; + * shift_reg_s [label="Shift register", shape=box]; + * {rank=same; mosi_s miso_s sck_s ss_s} + * label="SPI Slave"; + * rankdir=LR; + * } + * shift_reg:e -> mosi_m:w [label=""]; + * mosi_m:e -> mosi_s:w [label=""]; + * mosi_s:e -> shift_reg_s:w [label=""]; + * miso_s:w -> miso_m:e [label=""]; + * sck_m -> sck_s; + * ss_m -> ss_s; + * shift_reg_s:se -> miso_s:e [label=""]; + * miso_m:w -> shift_reg:sw [label=""]; + * rankdir=LR; + * } + * \enddot + * + * The different lines are as follows: + * - \b MISO Master Input Slave Output. The line where the data is shifted + * out from the slave and into the master. + * - \b MOSI Master Output Slave Input. The line where the data is shifted + * out from the master and into the slave. + * - \b SCK Serial Clock. Generated by the master device. + * - \b SS Slave Select. To initiate a transaction, the master must pull this + * line low. + * + * If the bus consists of several SPI slaves, they can be connected in parallel + * and the SPI master can use general I/O pins to control separate SS lines to + * each slave on the bus. + * + * It is also possible to connect all slaves in series. In this configuration, + * a common SS is provided to \c N slaves, enabling them simultaneously. The + * MISO from the \c N-1 slaves is connected to the MOSI on the next slave. The + * \c Nth slave connects its MISO back to the master. For a + * complete transaction, the master must shift \c N+1 characters. + * + * \subsection asfdoc_sam0_sercom_spi_chsize SPI Character Size + * The SPI character size is configurable to eight or nine bits. + * + * \subsection asfdoc_sam0_sercom_spi_master_mode Master Mode + * When configured as a master, the SS pin will be configured as an output. + * + * \subsubsection asfdoc_sam0_sercom_spi_master_mode_data_transfer Data Transfer + * Writing a character will start the SPI clock generator, and + * the character is transferred to the shift register when the shift + * register is empty. + * Once this is done, a new character can be written. + * As each character is shifted out from the master, a character is shifted in + * from the slave. If the receiver is enabled, the data is moved to the receive + * buffer at the completion of the frame and can be read. + * + * \subsection asfdoc_sam0_sercom_spi_slave_mode Slave Mode + * When configured as a slave, the SPI interface will remain inactive with MISO + * tri-stated as long as the SS pin is driven high. + * + * \subsubsection asfdoc_sam0_sercom_spi_slave_mode_data_transfer_slave Data Transfer + * The data register can be updated at any time. + * As the SPI slave shift register is clocked by SCK, a minimum of three SCK + * cycles are needed from the time new data is written, until the character is + * ready to be shifted out. If the shift register has not been loaded with + * data, the current contents will be transmitted. + * + * If constant transmission of data is needed in SPI slave mode, the system + * clock should be faster than SCK. + * If the receiver is enabled, the received character can be read from the + * receive buffer. When SS line is driven high, the slave will not receive any + * additional data. + * + * \subsubsection asfdoc_sam0_sercom_spi_slave_mode_addr_recognition Address Recognition + * When the SPI slave is configured with address recognition, the first + * character in a transaction is checked for an address match. If there is a + * match, the MISO output is enabled and the transaction is processed. + * If the address does not match, the complete transaction is ignored. + * + * If the device is asleep, it can be woken up by an address match in order + * to process the transaction. + * + * \note In master mode, an address packet is written by the + * \ref spi_select_slave function if the address_enabled configuration is + * set in the \ref spi_slave_inst_config struct. + * + * \subsection asfdoc_sam0_sercom_spi_data_modes Data Modes + * There are four combinations of SCK phase and polarity with respect to + * serial data. \ref asfdoc_sam0_spi_mode_table "The table below" shows the + * clock polarity (CPOL) and clock phase (CPHA) in the different modes. + * Leading edge is the first clock edge in a clock cycle and + * trailing edge is the last clock edge in a clock cycle. + * + * \anchor asfdoc_sam0_spi_mode_table + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
SPI Data Modes
ModeCPOLCPHALeading EdgeTrailing Edge
0 0 0 Rising, Sample Falling, Setup
1 0 1 Rising, Setup Falling, Sample
2 1 0 Falling, Sample Rising, Setup
3 1 1 Falling, Setup Rising, Sample
+ * + * + * \subsection asfdoc_sam0_sercom_spi_pads SERCOM Pads + * The SERCOM pads are automatically configured as seen in + * \ref asfdoc_sam0_spi_sercom_pad_table "the table below". If the receiver + * is disabled, the data input (MISO for master, MOSI for slave) can be used + * for other purposes. + * + * In master mode, the SS pin(s) must be configured using the \ref spi_slave_inst + * struct. + * + * \anchor asfdoc_sam0_spi_sercom_pad_table + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
SERCOM SPI Pad Usages
Pin Master SPI Slave SPI
MOSI Output Input
MISO Input Output
SCK Output Input
SS User defined output enable Input
+ * + * \subsection asfdoc_sam0_sercom_spi_sleep_modes Operation in Sleep Modes + * The SPI module can operate in all sleep modes by setting the run_in_standby + * option in the \ref spi_config struct. The operation in slave and master mode + * is shown in the table below. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
run_in_standby Slave Master
false Disabled, all reception is dropped GCLK is disabled when master is idle, wake on transmit complete
true Wake on reception GCLK is enabled while in sleep modes, wake on all interrupts
+ * + * \subsection asfdoc_sam0_sercom_spi_clock_generation Clock Generation + * In SPI master mode, the clock (SCK) is generated internally using the + * SERCOM baudrate generator. In SPI slave mode, the clock is provided by + * an external master on the SCK pin. This clock is used to directly clock + * the SPI shift register. + * + * \section asfdoc_sam0_sercom_spi_special_considerations Special Considerations + * \subsection pin_mux pinmux Settings + * The pin MUX settings must be configured properly, as not all settings + * can be used in different modes of operation. + * + * \section asfdoc_sam0_sercom_spi_extra_info Extra Information + * For extra information, see \ref asfdoc_sam0_sercom_spi_extra. This includes: + * - \ref asfdoc_sam0_sercom_spi_extra_acronyms + * - \ref asfdoc_sam0_sercom_spi_extra_dependencies + * - \ref asfdoc_sam0_sercom_spi_extra_workarounds + * - \ref asfdoc_sam0_sercom_spi_extra_history + * + * \section asfdoc_sam0_sercom_spi_examples Examples + * + * For a list of examples related to this driver, see + * \ref asfdoc_sam0_sercom_spi_exqsg. + * + * \section asfdoc_sam0_sercom_spi_api_overview API Overview + * @{ + */ + +#include +#include +#include +#include +#include +#include + +# if SPI_CALLBACK_MODE == true +# include +# endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if (CONF_SPI_MASTER_ENABLE == false) && (CONF_SPI_SLAVE_ENABLE == false) +#error "Not possible compile SPI driver, invalid driver configuration. Make sure that either/both CONF_SPI_MASTER_ENABLE/CONF_SPI_SLAVE_ENABLE is set to true." +#endif + +/** + * \name Driver Feature Definition + * Define SERCOM SPI features set according to different device family. + * @{ + */ +# if (SAMD21) || (SAMR21) || (SAMD11) || (SAMD10) || (SAML21) || (SAMDA1) || (SAMHA1) ||\ + (SAMHA0) || (SAML22) || (SAMC20) || (SAMC21) || (SAMD09) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) || defined(__DOXYGEN__) +/** SPI slave select low detection. */ +# define FEATURE_SPI_SLAVE_SELECT_LOW_DETECT +/** Slave select can be controlled by hardware. */ +# define FEATURE_SPI_HARDWARE_SLAVE_SELECT +/** SPI with error detect feature. */ +# define FEATURE_SPI_ERROR_INTERRUPT +/** SPI sync scheme version 2. */ +# define FEATURE_SPI_SYNC_SCHEME_VERSION_2 +# endif +/*@}*/ + +# ifndef PINMUX_DEFAULT +/** Default pinmux. */ +# define PINMUX_DEFAULT 0 +# endif + +# ifndef PINMUX_UNUSED +/** Unused pinmux. */ +# define PINMUX_UNUSED 0xFFFFFFFF +# endif + +# ifndef SPI_TIMEOUT +/** SPI timeout value. */ +# define SPI_TIMEOUT 10000 +# endif + +# if SPI_CALLBACK_MODE == true +/** + * \brief SPI Callback enum + * + * Callbacks for SPI callback driver. + * + * \note For slave mode, these callbacks will be called when a transaction + * is ended by the master pulling Slave Select high. + * + */ +enum spi_callback { + /** Callback for buffer transmitted */ + SPI_CALLBACK_BUFFER_TRANSMITTED, + /** Callback for buffer received */ + SPI_CALLBACK_BUFFER_RECEIVED, + /** Callback for buffers transceived */ + SPI_CALLBACK_BUFFER_TRANSCEIVED, + /** Callback for error */ + SPI_CALLBACK_ERROR, + /** + * Callback for transmission ended by master before the entire buffer was + * read or written from slave + */ + SPI_CALLBACK_SLAVE_TRANSMISSION_COMPLETE, +# ifdef FEATURE_SPI_SLAVE_SELECT_LOW_DETECT + /** Callback for slave select low */ + SPI_CALLBACK_SLAVE_SELECT_LOW, +# endif +# ifdef FEATURE_SPI_ERROR_INTERRUPT + /** Callback for combined error happen */ + SPI_CALLBACK_COMBINED_ERROR, +# endif +# if !defined(__DOXYGEN__) + /** Number of available callbacks */ + SPI_CALLBACK_N, +# endif +}; +# endif + +#if SPI_CALLBACK_MODE == true +# if !defined(__DOXYGEN__) +/** + * \internal SPI transfer directions + */ +enum _spi_direction { + /** Transfer direction is read */ + SPI_DIRECTION_READ, + /** Transfer direction is write */ + SPI_DIRECTION_WRITE, + /** Transfer direction is read and write */ + SPI_DIRECTION_BOTH, + /** No transfer */ + SPI_DIRECTION_IDLE, +}; +# endif +#endif + +/** + * \brief SPI Interrupt Flags + * + * Interrupt flags for the SPI module. + * + */ +enum spi_interrupt_flag { + /** + * This flag is set when the contents of the data register has been moved + * to the shift register and the data register is ready for new data + */ + SPI_INTERRUPT_FLAG_DATA_REGISTER_EMPTY = SERCOM_SPI_INTFLAG_DRE, + /** + * This flag is set when the contents of the shift register has been + * shifted out + */ + SPI_INTERRUPT_FLAG_TX_COMPLETE = SERCOM_SPI_INTFLAG_TXC, + /** This flag is set when data has been shifted into the data register */ + SPI_INTERRUPT_FLAG_RX_COMPLETE = SERCOM_SPI_INTFLAG_RXC, +# ifdef FEATURE_SPI_SLAVE_SELECT_LOW_DETECT + /** This flag is set when slave select low */ + SPI_INTERRUPT_FLAG_SLAVE_SELECT_LOW = SERCOM_SPI_INTFLAG_SSL, +# endif +# ifdef FEATURE_SPI_ERROR_INTERRUPT + /** This flag is set when combined error happen */ + SPI_INTERRUPT_FLAG_COMBINED_ERROR = SERCOM_SPI_INTFLAG_ERROR, +# endif +}; + +/** + * \brief SPI transfer modes enum + * + * SPI transfer mode. + */ +enum spi_transfer_mode { + /** Mode 0. Leading edge: rising, sample. Trailing edge: falling, setup */ + SPI_TRANSFER_MODE_0 = 0, + /** Mode 1. Leading edge: rising, setup. Trailing edge: falling, sample */ + SPI_TRANSFER_MODE_1 = SERCOM_SPI_CTRLA_CPHA, + /** Mode 2. Leading edge: falling, sample. Trailing edge: rising, setup */ + SPI_TRANSFER_MODE_2 = SERCOM_SPI_CTRLA_CPOL, + /** Mode 3. Leading edge: falling, setup. Trailing edge: rising, sample */ + SPI_TRANSFER_MODE_3 = SERCOM_SPI_CTRLA_CPHA | SERCOM_SPI_CTRLA_CPOL, +}; + +/** + * \brief SPI frame format enum + * + * Frame format for slave mode. + */ +enum spi_frame_format { + /** SPI frame */ + SPI_FRAME_FORMAT_SPI_FRAME = SERCOM_SPI_CTRLA_FORM(0), + /** SPI frame with address */ + SPI_FRAME_FORMAT_SPI_FRAME_ADDR = SERCOM_SPI_CTRLA_FORM(2), +}; + +/** + * \brief SPI signal MUX settings + * + * Set the functionality of the SERCOM pins. As not all combinations can be used + * in different modes of operation, proper combinations must be chosen according + * to the rest of the configuration. + * + * \note In master operation: DI is MISO, DO is MOSI. + * In slave operation: DI is MOSI, DO is MISO. + * + * See \ref asfdoc_sam0_sercom_spi_mux_settings for a description of the + * various MUX setting options. + */ +enum spi_signal_mux_setting { + /** SPI MUX combination A. DOPO: 0x0, DIPO: 0x0 */ + SPI_SIGNAL_MUX_SETTING_A = + (0x0 << SERCOM_SPI_CTRLA_DOPO_Pos) | + (0x0 << SERCOM_SPI_CTRLA_DIPO_Pos), + /** SPI MUX combination B. DOPO: 0x0, DIPO: 0x1 */ + SPI_SIGNAL_MUX_SETTING_B = + (0x0 << SERCOM_SPI_CTRLA_DOPO_Pos) | + (0x1 << SERCOM_SPI_CTRLA_DIPO_Pos), + /** SPI MUX combination C. DOPO: 0x0, DIPO: 0x2 */ + SPI_SIGNAL_MUX_SETTING_C = + (0x0 << SERCOM_SPI_CTRLA_DOPO_Pos) | + (0x2 << SERCOM_SPI_CTRLA_DIPO_Pos), + /** SPI MUX combination D. DOPO: 0x0, DIPO: 0x3 */ + SPI_SIGNAL_MUX_SETTING_D = + (0x0 << SERCOM_SPI_CTRLA_DOPO_Pos) | + (0x3 << SERCOM_SPI_CTRLA_DIPO_Pos), + /** SPI MUX combination E. DOPO: 0x1, DIPO: 0x0 */ + SPI_SIGNAL_MUX_SETTING_E = + (0x1 << SERCOM_SPI_CTRLA_DOPO_Pos) | + (0x0 << SERCOM_SPI_CTRLA_DIPO_Pos), + /** SPI MUX combination F. DOPO: 0x1, DIPO: 0x1 */ + SPI_SIGNAL_MUX_SETTING_F = + (0x1 << SERCOM_SPI_CTRLA_DOPO_Pos) | + (0x1 << SERCOM_SPI_CTRLA_DIPO_Pos), + /** SPI MUX combination G. DOPO: 0x1, DIPO: 0x2 */ + SPI_SIGNAL_MUX_SETTING_G = + (0x1 << SERCOM_SPI_CTRLA_DOPO_Pos) | + (0x2 << SERCOM_SPI_CTRLA_DIPO_Pos), + /** SPI MUX combination H. DOPO: 0x1, DIPO: 0x3 */ + SPI_SIGNAL_MUX_SETTING_H = + (0x1 << SERCOM_SPI_CTRLA_DOPO_Pos) | + (0x3 << SERCOM_SPI_CTRLA_DIPO_Pos), + /** SPI MUX combination I. DOPO: 0x2, DIPO: 0x0 */ + SPI_SIGNAL_MUX_SETTING_I = + (0x2 << SERCOM_SPI_CTRLA_DOPO_Pos) | + (0x0 << SERCOM_SPI_CTRLA_DIPO_Pos), + /** SPI MUX combination J. DOPO: 0x2, DIPO: 0x1 */ + SPI_SIGNAL_MUX_SETTING_J = + (0x2 << SERCOM_SPI_CTRLA_DOPO_Pos) | + (0x1 << SERCOM_SPI_CTRLA_DIPO_Pos), + /** SPI MUX combination K. DOPO: 0x2, DIPO: 0x2 */ + SPI_SIGNAL_MUX_SETTING_K = + (0x2 << SERCOM_SPI_CTRLA_DOPO_Pos) | + (0x2 << SERCOM_SPI_CTRLA_DIPO_Pos), + /** SPI MUX combination L. DOPO: 0x2, DIPO: 0x3 */ + SPI_SIGNAL_MUX_SETTING_L = + (0x2 << SERCOM_SPI_CTRLA_DOPO_Pos) | + (0x3 << SERCOM_SPI_CTRLA_DIPO_Pos), + /** SPI MUX combination M. DOPO: 0x3, DIPO: 0x0 */ + SPI_SIGNAL_MUX_SETTING_M = + (0x3 << SERCOM_SPI_CTRLA_DOPO_Pos) | + (0x0 << SERCOM_SPI_CTRLA_DIPO_Pos), + /** SPI MUX combination N. DOPO: 0x3, DIPO: 0x1 */ + SPI_SIGNAL_MUX_SETTING_N = + (0x3 << SERCOM_SPI_CTRLA_DOPO_Pos) | + (0x1 << SERCOM_SPI_CTRLA_DIPO_Pos), + /** SPI MUX combination O. DOPO: 0x3, DIPO: 0x2 */ + SPI_SIGNAL_MUX_SETTING_O = + (0x3 << SERCOM_SPI_CTRLA_DOPO_Pos) | + (0x2 << SERCOM_SPI_CTRLA_DIPO_Pos), + /** SPI MUX combination P. DOPO: 0x3, DIPO: 0x3 */ + SPI_SIGNAL_MUX_SETTING_P = + (0x3 << SERCOM_SPI_CTRLA_DOPO_Pos) | + (0x3 << SERCOM_SPI_CTRLA_DIPO_Pos), +}; + +/** + * \brief SPI address modes enum + * + * For slave mode when using the SPI frame with address format. + * + */ +enum spi_addr_mode { + /** + * \c address_mask in the \ref spi_config struct is used as a mask to the register + */ + SPI_ADDR_MODE_MASK = SERCOM_SPI_CTRLB_AMODE(0), + /** + * The slave responds to the two unique addresses in \c address and + * \c address_mask in the \ref spi_config struct + */ + SPI_ADDR_MODE_UNIQUE = SERCOM_SPI_CTRLB_AMODE(1), + /** + * The slave responds to the range of addresses between and including \c address + * and \c address_mask in the \ref spi_config struct + */ + SPI_ADDR_MODE_RANGE = SERCOM_SPI_CTRLB_AMODE(2), +}; + +/** + * \brief SPI modes enum + * + * SPI mode selection. + */ +enum spi_mode { + /** Master mode */ + SPI_MODE_MASTER = 1, + /** Slave mode */ + SPI_MODE_SLAVE = 0, +}; + +/** + * \brief SPI data order enum + * + * SPI data order. + * + */ +enum spi_data_order { + /** The LSB of the data is transmitted first */ + SPI_DATA_ORDER_LSB = SERCOM_SPI_CTRLA_DORD, + /** The MSB of the data is transmitted first */ + SPI_DATA_ORDER_MSB = 0, +}; + +/** + * \brief SPI character size enum + * + * SPI character size. + * + */ +enum spi_character_size { + /** 8-bit character */ + SPI_CHARACTER_SIZE_8BIT = SERCOM_SPI_CTRLB_CHSIZE(0), + /** 9-bit character */ + SPI_CHARACTER_SIZE_9BIT = SERCOM_SPI_CTRLB_CHSIZE(1), +}; + +# if SPI_CALLBACK_MODE == true +/** Prototype for the device instance */ +struct spi_module; + +/** Type of the callback functions */ +typedef void (*spi_callback_t)(struct spi_module *const module); + +# if !defined(__DOXYGEN__) +/** Prototype for the interrupt handler */ +extern void _spi_interrupt_handler(uint8_t instance); +# endif +# endif + +/** + * \brief SERCOM SPI driver software device instance structure. + * + * SERCOM SPI driver software instance structure, used to retain software state + * information of an associated hardware module instance. + * + * \note The fields of this structure should not be altered by the user + * application; they are reserved for module-internal use only. + */ +struct spi_module { +# if !defined(__DOXYGEN__) + /** SERCOM hardware module */ + Sercom *hw; + /** Module lock */ + volatile bool locked; + /** SPI mode */ + enum spi_mode mode; + /** SPI character size */ + enum spi_character_size character_size; + /** Receiver enabled */ + bool receiver_enabled; +# ifdef FEATURE_SPI_HARDWARE_SLAVE_SELECT + /** Enable Hardware Slave Select */ + bool master_slave_select_enable; +# endif +# if SPI_CALLBACK_MODE == true + /** Direction of transaction */ + volatile enum _spi_direction dir; + /** Array to store callback function pointers in */ + spi_callback_t callback[SPI_CALLBACK_N]; + /** Buffer pointer to where the next received character will be put */ + volatile uint8_t *rx_buffer_ptr; + /** Buffer pointer to where the next character will be transmitted from + **/ + volatile uint8_t *tx_buffer_ptr; + /** Remaining characters to receive */ + volatile uint16_t remaining_rx_buffer_length; + /** Remaining dummy characters to send when reading */ + volatile uint16_t remaining_dummy_buffer_length; + /** Remaining characters to transmit */ + volatile uint16_t remaining_tx_buffer_length; + /** Bit mask for callbacks registered */ + uint8_t registered_callback; + /** Bit mask for callbacks enabled */ + uint8_t enabled_callback; + /** Holds the status of the ongoing or last operation */ + volatile enum status_code status; +# endif +# endif +}; + +/** + * \brief SPI peripheral slave instance structure + * + * SPI peripheral slave software instance structure, used to configure the + * correct SPI transfer mode settings for an attached slave. See + * \ref spi_select_slave. + */ +struct spi_slave_inst { + /** Pin to use as slave select */ + uint8_t ss_pin; + /** Address recognition enabled in slave device */ + bool address_enabled; + /** Address of slave device */ + uint8_t address; +}; + +/** + * \brief SPI peripheral slave configuration structure + * + * SPI Peripheral slave configuration structure. + */ +struct spi_slave_inst_config { + /** Pin to use as slave select */ + uint8_t ss_pin; + /** Enable address */ + bool address_enabled; + /** Address of slave */ + uint8_t address; +}; + +/** + * \brief SPI Master configuration structure + * + * SPI Master configuration structure. + */ +struct spi_master_config { + /** Baud rate */ + uint32_t baudrate; +}; + +/** + * \brief SPI slave configuration structure + * + * SPI slave configuration structure. + */ +struct spi_slave_config { + /** Frame format */ + enum spi_frame_format frame_format; + /** Address mode */ + enum spi_addr_mode address_mode; + /** Address */ + uint8_t address; + /** Address mask */ + uint8_t address_mask; + /** Preload data to the shift register while SS is high */ + bool preload_enable; +}; + +/** + * \brief SPI configuration structure + * + * Configuration structure for an SPI instance. This structure should be + * initialized by the \ref spi_get_config_defaults function before being + * modified by the user application. + */ +struct spi_config { + /** SPI mode */ + enum spi_mode mode; + /** Data order */ + enum spi_data_order data_order; + /** Transfer mode */ + enum spi_transfer_mode transfer_mode; + /** MUX setting */ + enum spi_signal_mux_setting mux_setting; + /** SPI character size */ + enum spi_character_size character_size; + /** Enabled in sleep modes */ + bool run_in_standby; + /** Enable receiver */ + bool receiver_enable; +# ifdef FEATURE_SPI_SLAVE_SELECT_LOW_DETECT + /** Enable Slave Select Low Detect */ + bool select_slave_low_detect_enable; +# endif +# ifdef FEATURE_SPI_HARDWARE_SLAVE_SELECT + /** Enable Master Slave Select */ + bool master_slave_select_enable; +# endif + /** Union for slave or master specific configuration */ + union { + /** Slave specific configuration */ + struct spi_slave_config slave; + /** Master specific configuration */ + struct spi_master_config master; + } mode_specific; + /** GCLK generator to use as clock source */ + enum gclk_generator generator_source; + /** PAD0 pinmux */ + uint32_t pinmux_pad0; + /** PAD1 pinmux */ + uint32_t pinmux_pad1; + /** PAD2 pinmux */ + uint32_t pinmux_pad2; + /** PAD3 pinmux */ + uint32_t pinmux_pad3; +}; + +/** + * \brief Determines if the SPI module is currently synchronizing to the bus. + * + * This function will check if the underlying hardware peripheral module is + * currently synchronizing across multiple clock domains to the hardware bus. + * This function can be used to delay further operations on the module until it + * is ready. + * + * \param[in] module SPI hardware module + * + * \return Synchronization status of the underlying hardware module. + * \retval true Module synchronization is ongoing + * \retval false Module synchronization is not ongoing + * + */ +static inline bool spi_is_syncing( + struct spi_module *const module) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + SercomSpi *const spi_module = &(module->hw->SPI); + +# ifdef FEATURE_SPI_SYNC_SCHEME_VERSION_2 + /* Return synchronization status */ + return (spi_module->SYNCBUSY.reg); +# else + /* Return synchronization status */ + return (spi_module->STATUS.reg & SERCOM_SPI_STATUS_SYNCBUSY); +# endif +} + +/** + * \name Driver Initialization and Configuration + * @{ + */ + +/** + * \brief Initializes an SPI configuration structure to default values + * + * This function will initialize a given SPI configuration structure to a set + * of known default values. This function should be called on any new + * instance of the configuration structures before being modified by the + * user application. + * + * The default configuration is as follows: + * \li Master mode enabled + * \li MSB of the data is transmitted first + * \li Transfer mode 0 + * \li MUX Setting D + * \li Character size eight bits + * \li Not enabled in sleep mode + * \li Receiver enabled + * \li Baudrate 100000 + * \li Default pinmux settings for all pads + * \li GCLK generator 0 + * + * \param[out] config Configuration structure to initialize to default values + */ +static inline void spi_get_config_defaults( + struct spi_config *const config) +{ + /* Sanity check arguments */ + Assert(config); + + /* Default configuration values */ + config->mode = SPI_MODE_MASTER; + config->data_order = SPI_DATA_ORDER_MSB; + config->transfer_mode = SPI_TRANSFER_MODE_0; + config->mux_setting = SPI_SIGNAL_MUX_SETTING_D; + config->character_size = SPI_CHARACTER_SIZE_8BIT; + config->run_in_standby = false; + config->receiver_enable = true; +# ifdef FEATURE_SPI_SLAVE_SELECT_LOW_DETECT + config->select_slave_low_detect_enable= true; +# endif +# ifdef FEATURE_SPI_HARDWARE_SLAVE_SELECT + config->master_slave_select_enable= false; +# endif + config->generator_source = GCLK_GENERATOR_0; + + /* Clear mode specific config */ + memset(&(config->mode_specific), 0, sizeof(config->mode_specific)); + + /* Master config defaults */ + config->mode_specific.master.baudrate = 100000; + + /* pinmux config defaults */ + config->pinmux_pad0 = PINMUX_DEFAULT; + config->pinmux_pad1 = PINMUX_DEFAULT; + config->pinmux_pad2 = PINMUX_DEFAULT; + config->pinmux_pad3 = PINMUX_DEFAULT; + +}; + +/** + * \brief Initializes an SPI peripheral slave device configuration structure to default values + * + * This function will initialize a given SPI slave device configuration + * structure to a set of known default values. This function should be called + * on any new instance of the configuration structures before being modified by + * the user application. + * + * The default configuration is as follows: + * \li Slave Select on GPIO pin 10 + * \li Addressing not enabled + * + * \param[out] config Configuration structure to initialize to default values + */ +static inline void spi_slave_inst_get_config_defaults( + struct spi_slave_inst_config *const config) +{ + Assert(config); + + config->ss_pin = 10; + config->address_enabled = false; + config->address = 0; +} + +/** + * \brief Attaches an SPI peripheral slave + * + * This function will initialize the software SPI peripheral slave, based on + * the values of the config struct. The slave can then be selected and + * optionally addressed by the \ref spi_select_slave function. + * + * \param[out] slave Pointer to the software slave instance struct + * \param[in] config Pointer to the config struct + * + */ +static inline void spi_attach_slave( + struct spi_slave_inst *const slave, + const struct spi_slave_inst_config *const config) +{ + Assert(slave); + Assert(config); + + slave->ss_pin = config->ss_pin; + slave->address_enabled = config->address_enabled; + slave->address = config->address; + + /* Get default config for pin */ + struct port_config pin_conf; + port_get_config_defaults(&pin_conf); + + /* Edit config to set the pin as output */ + pin_conf.direction = PORT_PIN_DIR_OUTPUT; + + /* Set config on Slave Select pin */ + port_pin_set_config(slave->ss_pin, &pin_conf); + port_pin_set_output_level(slave->ss_pin, true); +} + +enum status_code spi_init( + struct spi_module *const module, + Sercom *const hw, + const struct spi_config *const config); + +/** @} */ + +/** + * \name Enable/Disable + * @{ + */ + +/** + * \brief Enables the SERCOM SPI module + * + * This function will enable the SERCOM SPI module. + * + * \param[in,out] module Pointer to the software instance struct + */ +static inline void spi_enable( + struct spi_module *const module) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + SercomSpi *const spi_module = &(module->hw->SPI); + +# if SPI_CALLBACK_MODE == true + system_interrupt_enable(_sercom_get_interrupt_vector(module->hw)); +# endif + + while (spi_is_syncing(module)) { + /* Wait until the synchronization is complete */ + } + + /* Enable SPI */ + spi_module->CTRLA.reg |= SERCOM_SPI_CTRLA_ENABLE; +} + +/** + * \brief Disables the SERCOM SPI module + * + * This function will disable the SERCOM SPI module. + * + * \param[in,out] module Pointer to the software instance struct + */ +static inline void spi_disable( + struct spi_module *const module) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + SercomSpi *const spi_module = &(module->hw->SPI); + +# if SPI_CALLBACK_MODE == true + system_interrupt_disable(_sercom_get_interrupt_vector(module->hw)); +# endif + + while (spi_is_syncing(module)) { + /* Wait until the synchronization is complete */ + } + + /* Disbale interrupt */ + spi_module->INTENCLR.reg = SERCOM_SPI_INTENCLR_MASK; + /* Clear interrupt flag */ + spi_module->INTFLAG.reg = SERCOM_SPI_INTFLAG_MASK; + + /* Disable SPI */ + spi_module->CTRLA.reg &= ~SERCOM_SPI_CTRLA_ENABLE; +} + +void spi_reset( + struct spi_module *const module); + +/** @} */ + +enum status_code spi_set_baudrate( + struct spi_module *const module, + uint32_t baudrate); + +/** + * \name Lock/Unlock + * @{ + */ + +/** + * \brief Attempt to get lock on driver instance + * + * This function checks the instance's lock, which indicates whether or not it + * is currently in use, and sets the lock if it was not already set. + * + * The purpose of this is to enable exclusive access to driver instances, so + * that, e.g., transactions by different services will not interfere with each + * other. + * + * \param[in,out] module Pointer to the driver instance to lock + * + * \retval STATUS_OK If the module was locked + * \retval STATUS_BUSY If the module was already locked + */ +static inline enum status_code spi_lock(struct spi_module *const module) +{ + enum status_code status; + + system_interrupt_enter_critical_section(); + + if (module->locked) { + status = STATUS_BUSY; + } else { + module->locked = true; + status = STATUS_OK; + } + + system_interrupt_leave_critical_section(); + + return status; +} + +/** + * \brief Unlock driver instance + * + * This function clears the instance lock, indicating that it is available for + * use. + * + * \param[in,out] module Pointer to the driver instance to lock + * + * \retval STATUS_OK If the module was locked + * \retval STATUS_BUSY If the module was already locked + */ +static inline void spi_unlock(struct spi_module *const module) +{ + module->locked = false; +} + +/** @} */ + +/** + * \name Ready to Write/Read + * @{ + */ + + /** + * \brief Checks if the SPI in master mode has shifted out last data, or if the master has ended the transfer in slave mode. + * + * This function will check if the SPI master module has shifted out last data, + * or if the slave select pin has been drawn high by the master for the SPI + * slave module. + * + * \param[in] module Pointer to the software instance struct + * + * \return Indication of whether any writes are ongoing. + * \retval true If the SPI master module has shifted out data, or slave select + * has been drawn high for SPI slave + * \retval false If the SPI master module has not shifted out data + */ +static inline bool spi_is_write_complete( + struct spi_module *const module) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + SercomSpi *const spi_module = &(module->hw->SPI); + + /* Check interrupt flag */ + return (spi_module->INTFLAG.reg & SERCOM_SPI_INTFLAG_TXC); +} + + /** + * \brief Checks if the SPI module is ready to write data + * + * This function will check if the SPI module is ready to write data. + * + * \param[in] module Pointer to the software instance struct + * + * \return Indication of whether the module is ready to read data or not. + * \retval true If the SPI module is ready to write data + * \retval false If the SPI module is not ready to write data + */ +static inline bool spi_is_ready_to_write( + struct spi_module *const module) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + SercomSpi *const spi_module = &(module->hw->SPI); + + /* Check interrupt flag */ + return (spi_module->INTFLAG.reg & SERCOM_SPI_INTFLAG_DRE); +} + +/** + * \brief Checks if the SPI module is ready to read data + * + * This function will check if the SPI module is ready to read data. + * + * \param[in] module Pointer to the software instance struct + * + * \return Indication of whether the module is ready to read data or not. + * \retval true If the SPI module is ready to read data + * \retval false If the SPI module is not ready to read data + */ +static inline bool spi_is_ready_to_read( + struct spi_module *const module) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + SercomSpi *const spi_module = &(module->hw->SPI); + + /* Check interrupt flag */ + return (spi_module->INTFLAG.reg & SERCOM_SPI_INTFLAG_RXC); +} +/** @} */ + +/** + * \name Read/Write + * @{ + */ + + /** + * \brief Transfers a single SPI character + * + * This function will send a single SPI character via SPI and ignore any data + * shifted in by the connected device. To both send and receive data, use the + * \ref spi_transceive_wait function or use the \ref spi_read function after + * writing a character. The \ref spi_is_ready_to_write function + * should be called before calling this function. + * + * Note that this function does not handle the SS (Slave Select) + * pin(s) in master mode; this must be handled from the user application. + * + * \note In slave mode, the data will not be transferred before a master + * initiates a transaction. + * + * \param[in] module Pointer to the software instance struct + * \param[in] tx_data Data to transmit + * + * \return Status of the procedure. + * \retval STATUS_OK If the data was written + * \retval STATUS_BUSY If the last write was not completed + */ +static inline enum status_code spi_write( + struct spi_module *module, + uint16_t tx_data) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + SercomSpi *const spi_module = &(module->hw->SPI); + + /* Check if the data register has been copied to the shift register */ + if (!spi_is_ready_to_write(module)) { + /* Data register has not been copied to the shift register, return */ + return STATUS_BUSY; + } + + /* Write the character to the DATA register */ + spi_module->DATA.reg = tx_data & SERCOM_SPI_DATA_MASK; + + return STATUS_OK; +} + +enum status_code spi_write_buffer_wait( + struct spi_module *const module, + const uint8_t *tx_data, + uint16_t length); + +/** + * \brief Reads last received SPI character + * + * This function will return the last SPI character shifted into the receive + * register by the \ref spi_write function. + * + * \note The \ref spi_is_ready_to_read function should be called before calling + * this function. + * + * \note Receiver must be enabled in the configuration. + * + * \param[in] module Pointer to the software instance struct + * \param[out] rx_data Pointer to store the received data + * + * \returns Status of the read operation. + * \retval STATUS_OK If data was read + * \retval STATUS_ERR_IO If no data is available + * \retval STATUS_ERR_OVERFLOW If the data is overflown + */ +static inline enum status_code spi_read( + struct spi_module *const module, + uint16_t *rx_data) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + SercomSpi *const spi_module = &(module->hw->SPI); + + /* Check if data is ready to be read */ + if (!spi_is_ready_to_read(module)) { + /* No data has been received, return */ + return STATUS_ERR_IO; + } + + /* Return value */ + enum status_code retval = STATUS_OK; + + /* Check if data is overflown */ + if (spi_module->STATUS.reg & SERCOM_SPI_STATUS_BUFOVF) { + retval = STATUS_ERR_OVERFLOW; + /* Clear overflow flag */ + spi_module->STATUS.reg = SERCOM_SPI_STATUS_BUFOVF; + } + + /* Read the character from the DATA register */ + if (module->character_size == SPI_CHARACTER_SIZE_9BIT) { + *rx_data = (spi_module->DATA.reg & SERCOM_SPI_DATA_MASK); + } else { + *rx_data = (uint8_t)spi_module->DATA.reg; + } + + return retval; +} + +enum status_code spi_read_buffer_wait( + struct spi_module *const module, + uint8_t *rx_data, + uint16_t length, + uint16_t dummy); + +enum status_code spi_transceive_wait( + struct spi_module *const module, + uint16_t tx_data, + uint16_t *rx_data); + +enum status_code spi_transceive_buffer_wait( + struct spi_module *const module, + uint8_t *tx_data, + uint8_t *rx_data, + uint16_t length); + +enum status_code spi_select_slave( + struct spi_module *const module, + struct spi_slave_inst *const slave, + bool select); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +/** @} */ + + +/** + * \page asfdoc_sam0_sercom_spi_extra Extra Information for SERCOM SPI Driver + * + * \section asfdoc_sam0_sercom_spi_extra_acronyms Acronyms + * Below is a table listing the acronyms used in this module, along with their + * intended meanings. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
AcronymDescription
SERCOMSerial Communication Interface
SPISerial Peripheral Interface
SCKSerial Clock
MOSIMaster Output Slave Input
MISOMaster Input Slave Output
SSSlave Select
DIOData Input Output
DOData Output
DIData Input
DMADirect Memory Access
+ * + * \section asfdoc_sam0_sercom_spi_extra_dependencies Dependencies + * The SPI driver has the following dependencies: + * \li \ref asfdoc_sam0_system_pinmux_group "System Pin Multiplexer Driver" + * + * + * \section asfdoc_sam0_sercom_spi_extra_workarounds Workarounds Implemented by Driver + * No workarounds in driver. + * + * \section asfdoc_sam0_sercom_spi_extra_history Module History + * An overview of the module history is presented in the table below, with + * details on the enhancements and fixes made to the module since its first + * release. The current version of this corresponds to the newest version in the table. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Changelog
Added new features as below: + * \li Slave select low detect + * \li Hardware slave select + * \li DMA support
Edited slave part of write and transceive buffer functions to ensure + * that second character is sent at the right time
Renamed the anonymous union in \c struct spi_config to + * \c mode_specific
Initial Release
+ */ + +/** + * \page asfdoc_sam0_sercom_spi_exqsg Examples for SERCOM SPI Driver + * + * This is a list of the available Quick Start guides (QSGs) and example + * applications for \ref asfdoc_sam0_sercom_spi_group. QSGs are simple examples with + * step-by-step instructions to configure and use this driver in a selection of + * use cases. Note that a QSG can be compiled as a standalone application or be + * added to the user application. + * + * - \subpage asfdoc_sam0_sercom_spi_master_basic_use + * - \subpage asfdoc_sam0_sercom_spi_slave_basic_use + * \if SPI_CALLBACK_MODE + * - \subpage asfdoc_sam0_sercom_spi_master_callback_use + * - \subpage asfdoc_sam0_sercom_spi_slave_callback_use + * \endif + * - \subpage asfdoc_sam0_sercom_spi_dma_use_case + */ + + /** + * \page asfdoc_sam0_sercom_spi_mux_settings MUX Settings + * + * The following lists the possible internal SERCOM module pad function + * assignments for the four SERCOM pads in both SPI Master and SPI Slave + * modes. They are combinations of DOPO and DIPO in CTRLA. + * Note that this is in addition to the physical GPIO pin MUX of the device, + * and can be used in conjunction to optimize the serial data pin-out. + * + * \section asfdoc_sam0_sercom_spi_mux_settings_master Master Mode Settings + * The following table describes the SERCOM pin functionalities for the various + * MUX settings, whilst in SPI Master mode. + * + * \note If MISO is unlisted, the SPI receiver must not be enabled for the + * given MUX setting. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
CombinationDOPO / DIPOSERCOM PAD[0]SERCOM PAD[1]SERCOM PAD[2]SERCOM PAD[3]
A0x0 / 0x0MOSISCK--
B0x0 / 0x1MOSISCK--
C0x0 / 0x2MOSISCKMISO-
D0x0 / 0x3MOSISCK-MISO
E0x1 / 0x0MISO-MOSISCK
F0x1 / 0x1-MISOMOSISCK
G0x1 / 0x2--MOSISCK
H0x1 / 0x3--MOSISCK
I0x2 / 0x0MISOSCK-MOSI
J0x2 / 0x1-SCK-MOSI
K0x2 / 0x2-SCKMISOMOSI
L0x2 / 0x3-SCK-MOSI
M0x3 / 0x0MOSI--SCK
N0x3 / 0x1MOSIMISO-SCK
O0x3 / 0x2MOSI-MISOSCK
P0x3 / 0x3MOSI--SCK
+ * + * + * \section asfdoc_sam0_sercom_spi_mux_settings_slave Slave Mode Settings + * The following table describes the SERCOM pin functionalities for the various + * MUX settings, whilst in SPI Slave mode. + * + * \note If MISO is unlisted, the SPI receiver must not be enabled for the + * given MUX setting. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
CombinationDOPO / DIPOSERCOM PAD[0]SERCOM PAD[1]SERCOM PAD[2]SERCOM PAD[3]
A0x0 / 0x0MISOSCK/SS-
B0x0 / 0x1MISOSCK/SS-
C0x0 / 0x2MISOSCK/SS-
D0x0 / 0x3MISOSCK/SSMOSI
E0x1 / 0x0MOSI/SSMISOSCK
F0x1 / 0x1-/SSMISOSCK
G0x1 / 0x2-/SSMISOSCK
H0x1 / 0x3-/SSMISOSCK
I0x2 / 0x0MOSISCK/SSMISO
J0x2 / 0x1-SCK/SSMISO
K0x2 / 0x2-SCK/SSMISO
L0x2 / 0x3-SCK/SSMISO
M0x3 / 0x0MISO/SS-SCK
N0x3 / 0x1MISO/SS-SCK
O0x3 / 0x2MISO/SSMOSISCK
P0x3 / 0x3MISO/SS-SCK
+ * + * + * + * \page asfdoc_sam0_sercom_spi_document_revision_history Document Revision History + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Doc. Rev.DateComments
42115E12/2015Add SAM L21/L22, SAM DA1, SAM D09, SAMR30/R34 and SAM C21 support
42115D12/2014Add SAM R21/D10/D11 support
42115C01/2014Add SAM D21 support
42115B11/2013Replaced the pad multiplexing documentation with a condensed table
42115A06/2013Initial release
+ */ + +#endif /* SPI_H_INCLUDED */ diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/usart/quick_start/qs_usart_basic_use.h b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/usart/quick_start/qs_usart_basic_use.h new file mode 100644 index 000000000..834a213f5 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/usart/quick_start/qs_usart_basic_use.h @@ -0,0 +1,106 @@ +/** + * \file + * + * \brief SAM USART Quick Start + * + * Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ + +/** + * \page asfdoc_sam0_sercom_usart_basic_use_case Quick Start Guide for SERCOM USART - Basic + * + * This quick start will echo back characters typed into the terminal. In this + * use case the USART will be configured with the following settings: + * - Asynchronous mode + * - 9600 Baudrate + * - 8-bits, No Parity and one Stop Bit + * - TX and RX enabled and connected to the Xplained Pro Embedded Debugger virtual COM port + * + * \section asfdoc_sam0_sercom_usart_basic_use_case_setup Setup + * + * \subsection asfdoc_sam0_sercom_usart_basic_use_case_prereq Prerequisites + * There are no special setup requirements for this use-case. + * + * \subsection asfdoc_sam0_usart_basic_use_case_setup_code Code + * Add to the main application source file, outside of any functions: + * \snippet qs_usart_basic_use.c module_inst + * + * Copy-paste the following setup code to your user application: + * \snippet qs_usart_basic_use.c setup + * + * Add to user application initialization (typically the start of \c main()): + * \snippet qs_usart_basic_use.c setup_init + * + * \subsection asfdoc_sam0_usart_basic_use_case_setup_flow Workflow + * -# Create a module software instance structure for the USART module to store + * the USART driver state while it is in use. + * \snippet qs_usart_basic_use.c module_inst + * \note This should never go out of scope as long as the module is in use. + * In most cases, this should be global. + * + * -# Configure the USART module. + * -# Create a USART module configuration struct, which can be filled out to + * adjust the configuration of a physical USART peripheral. + * \snippet qs_usart_basic_use.c setup_config + * -# Initialize the USART configuration struct with the module's default values. + * \snippet qs_usart_basic_use.c setup_config_defaults + * \note This should always be performed before using the configuration + * struct to ensure that all values are initialized to known default + * settings. + * + * -# Alter the USART settings to configure the physical pinout, baudrate, and + * other relevant parameters. + * \snippet qs_usart_basic_use.c setup_change_config + * -# Configure the USART module with the desired settings, retrying while the + * driver is busy until the configuration is stressfully set. + * \snippet qs_usart_basic_use.c setup_set_config + * -# Enable the USART module. + * \snippet qs_usart_basic_use.c setup_enable + * + * + * \section asfdoc_sam0_usart_basic_use_case_main Use Case + * + * \subsection asfdoc_sam0_usart_basic_use_case_main_code Code + * Copy-paste the following code to your user application: + * \snippet qs_usart_basic_use.c main + * + * \subsection asfdoc_sam0_usart_basic_use_case_main_flow Workflow + * -# Send a string to the USART to show the demo is running, blocking until + * all characters have been sent. + * \snippet qs_usart_basic_use.c main_send_string + * -# Enter an infinite loop to continuously echo received values on the USART. + * \snippet qs_usart_basic_use.c main_loop + * -# Perform a blocking read of the USART, storing the received character into + * the previously declared temporary variable. + * \snippet qs_usart_basic_use.c main_read + * -# Echo the received variable back to the USART via a blocking write. + * \snippet qs_usart_basic_use.c main_write + */ +/* + * Support and FAQ: visit Microchip Support + */ diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/usart/quick_start_callback/qs_usart_callback.h b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/usart/quick_start_callback/qs_usart_callback.h new file mode 100644 index 000000000..9cb8dca0b --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/usart/quick_start_callback/qs_usart_callback.h @@ -0,0 +1,120 @@ +/** + * \file + * + * \brief SAM USART Quick Start + * + * Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ + +/** + * \page asfdoc_sam0_sercom_usart_callback_use_case Quick Start Guide for SERCOM USART - Callback + * + * This quick start will echo back characters typed into the terminal, using + * asynchronous TX and RX callbacks from the USART peripheral. In this use case + * the USART will be configured with the following settings: + * - Asynchronous mode + * - 9600 Baudrate + * - 8-bits, No Parity and one Stop Bit + * - TX and RX enabled and connected to the Xplained Pro Embedded Debugger virtual COM port + * + * \section asfdoc_sam0_sercom_usart_callback_use_case_setup Setup + * + * \subsection asfdoc_sam0_sercom_usart_callback_use_case_prereq Prerequisites + * There are no special setup requirements for this use-case. + * + * \subsection asfdoc_sam0_usart_callback_use_case_setup_code Code + * Add to the main application source file, outside of any functions: + * \snippet qs_usart_callback.c module_inst + * \snippet qs_usart_callback.c rx_buffer_var + * + * Copy-paste the following callback function code to your user application: + * \snippet qs_usart_callback.c callback_funcs + * + * Copy-paste the following setup code to your user application: + * \snippet qs_usart_callback.c setup + * + * Add to user application initialization (typically the start of \c main()): + * \snippet qs_usart_callback.c setup_init + * + * \subsection asfdoc_sam0_usart_callback_use_case_setup_flow Workflow + * -# Create a module software instance structure for the USART module to store + * the USART driver state while it is in use. + * \snippet qs_usart_callback.c module_inst + * \note This should never go out of scope as long as the module is in use. + * In most cases, this should be global. + * + * -# Configure the USART module. + * -# Create a USART module configuration struct, which can be filled out to + * adjust the configuration of a physical USART peripheral. + * \snippet qs_usart_callback.c setup_config + * -# Initialize the USART configuration struct with the module's default values. + * \snippet qs_usart_callback.c setup_config_defaults + * \note This should always be performed before using the configuration + * struct to ensure that all values are initialized to known default + * settings. + * + * -# Alter the USART settings to configure the physical pinout, baudrate, and + * other relevant parameters. + * \snippet qs_usart_callback.c setup_change_config + * -# Configure the USART module with the desired settings, retrying while the + * driver is busy until the configuration is stressfully set. + * \snippet qs_usart_callback.c setup_set_config + * -# Enable the USART module. + * \snippet qs_usart_callback.c setup_enable + * -# Configure the USART callbacks. + * -# Register the TX and RX callback functions with the driver. + * \snippet qs_usart_callback.c setup_register_callbacks + * -# Enable the TX and RX callbacks so that they will be called by the driver + * when appropriate. + * \snippet qs_usart_callback.c setup_enable_callbacks + * + * \section asfdoc_sam0_usart_callback_use_case_main Use Case + * + * \subsection asfdoc_sam0_usart_callback_use_case_main_code Code + * Copy-paste the following code to your user application: + * \snippet qs_usart_callback.c main + * + * \subsection asfdoc_sam0_usart_callback_use_case_main_flow Workflow + * -# Enable global interrupts, so that the callbacks can be fired. + * \snippet qs_usart_callback.c enable_global_interrupts + * -# Send a string to the USART to show the demo is running, blocking until + * all characters have been sent. + * \snippet qs_usart_callback.c main_send_string + * -# Enter an infinite loop to continuously echo received values on the USART. + * \snippet qs_usart_callback.c main_loop + * -# Perform an asynchronous read of the USART, which will fire the registered + * callback when characters are received. + * \snippet qs_usart_callback.c main_read + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#include +#include + diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/usart/quick_start_dma/qs_usart_dma_use.h b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/usart/quick_start_dma/qs_usart_dma_use.h new file mode 100644 index 000000000..f2f56fcc4 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/usart/quick_start_dma/qs_usart_dma_use.h @@ -0,0 +1,208 @@ +/** + * \file + * + * \brief SAM Quick Start Guide for Using Usart driver with DMA + * + * Copyright (c) 2014-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +/** + * \page asfdoc_sam0_sercom_usart_dma_use_case Quick Start Guide for Using DMA with SERCOM USART + * + * The supported board list: + * - SAM D21 Xplained Pro + * - SAM R21 Xplained Pro + * - SAM D11 Xplained Pro + * - SAM DA1 Xplained Pro + * - SAM HA1G16A Xplained Pro + * - SAM L21 Xplained Pro + * - SAM L22 Xplained Pro + * - SAM C21 Xplained Pro + * + * This quick start will receive eight bytes of data from the PC terminal and transmit back the string + * to the terminal through DMA. In this use case the USART will be configured with the following + * settings: + * - Asynchronous mode + * - 9600 Baudrate + * - 8-bits, No Parity and one Stop Bit + * - TX and RX enabled and connected to the Xplained Pro Embedded Debugger virtual COM port + * + * \section asfdoc_sam0_sercom_usart_dma_use_case_setup Setup + * + * \subsection asfdoc_sam0_sercom_usart_dma_use_case_prereq Prerequisites + * There are no special setup requirements for this use-case. + * + * \subsection asfdoc_sam0_usart_dma_use_case_setup_code Code + * Add to the main application source file, outside of any functions: + * \snippet qs_usart_dma_use.c module_inst + * \snippet qs_usart_dma_use.c dma_resource + * \snippet qs_usart_dma_use.c usart_buffer + * \snippet qs_usart_dma_use.c transfer_descriptor + * + * Copy-paste the following setup code to your user application: + * \snippet qs_usart_dma_use.c setup + * + * Add to user application initialization (typically the start of \c main()): + * \snippet qs_usart_dma_use.c setup_init + * + * \subsection asfdoc_sam0_usart_dma_use_case_setup_flow Workflow + * + * \subsubsection asfdoc_sam0_usart_dma_use_case_setup_flow_inst Create variables + * -# Create a module software instance structure for the USART module to store + * the USART driver state while it is in use. + * \snippet qs_usart_dma_use.c module_inst + * \note This should never go out of scope as long as the module is in use. + * In most cases, this should be global. + * + * -# Create module software instance structures for DMA resources to store + * the DMA resource state while it is in use. + * \snippet qs_usart_dma_use.c dma_resource + * \note This should never go out of scope as long as the module is in use. + * In most cases, this should be global. + * + * -# Create a buffer to store the data to be transferred /received. + * \snippet qs_usart_dma_use.c usart_buffer + * -# Create DMA transfer descriptors for RX/TX. + * \snippet qs_usart_dma_use.c transfer_descriptor + * + * \subsubsection asfdoc_sam0_usart_dma_use_case_setup_flow_usart Configure the USART + * -# Create a USART module configuration struct, which can be filled out to + * adjust the configuration of a physical USART peripheral. + * \snippet qs_usart_dma_use.c setup_config + * -# Initialize the USART configuration struct with the module's default values. + * \snippet qs_usart_dma_use.c setup_config_defaults + * \note This should always be performed before using the configuration + * struct to ensure that all values are initialized to known default + * settings. + * + * -# Alter the USART settings to configure the physical pinout, baudrate, and + * other relevant parameters. + * \snippet qs_usart_dma_use.c setup_change_config + * -# Configure the USART module with the desired settings, retrying while the + * driver is busy until the configuration is stressfully set. + * \snippet qs_usart_dma_use.c setup_set_config + * -# Enable the USART module. + * \snippet qs_usart_dma_use.c setup_enable + * + * \subsubsection asfdoc_sam0_usart_dma_use_case_setup_flow_dma Configure DMA + * -# Create a callback function of receiver done. + * \snippet qs_usart_dma_use.c transfer_done_rx + * + * -# Create a callback function of transmission done. + * \snippet qs_usart_dma_use.c transfer_done_tx + * + * -# Create a DMA resource configuration structure, which can be filled out to + * adjust the configuration of a single DMA transfer. + * \snippet qs_usart_dma_use.c setup_rx_1 + * + * -# Initialize the DMA resource configuration struct with the module's + * default values. + * \snippet qs_usart_dma_use.c setup_rx_2 + * \note This should always be performed before using the configuration + * struct to ensure that all values are initialized to known default + * settings. + * + * -# Set extra configurations for the DMA resource. It is using peripheral + * trigger. SERCOM TX empty trigger causes a beat transfer in + * this example. + * \snippet qs_usart_dma_use.c setup_rx_3 + * + * -# Allocate a DMA resource with the configurations. + * \snippet qs_usart_dma_use.c setup_rx_4 + * + * -# Create a DMA transfer descriptor configuration structure, which can be + * filled out to adjust the configuration of a single DMA transfer. + * \snippet qs_usart_dma_use.c setup_rx_5 + * + * -# Initialize the DMA transfer descriptor configuration struct with the module's + * default values. + * \snippet qs_usart_dma_use.c setup_rx_6 + * \note This should always be performed before using the configuration + * struct to ensure that all values are initialized to known default + * settings. + * + * -# Set the specific parameters for a DMA transfer with transfer size, source + * address, and destination address. + * \snippet qs_usart_dma_use.c setup_rx_7 + * + * -# Create the DMA transfer descriptor. + * \snippet qs_usart_dma_use.c setup_rx_8 + * + * -# Create a DMA resource configuration structure for TX, which can be filled + * out to adjust the configuration of a single DMA transfer. + * \snippet qs_usart_dma_use.c setup_tx_1 + * + * -# Initialize the DMA resource configuration struct with the module's + * default values. + * \snippet qs_usart_dma_use.c setup_tx_2 + * \note This should always be performed before using the configuration + * struct to ensure that all values are initialized to known default + * settings. + * + * -# Set extra configurations for the DMA resource. It is using peripheral + * trigger. SERCOM RX Ready trigger causes a beat transfer in + * this example. + * \snippet qs_usart_dma_use.c setup_tx_3 + * + * -# Allocate a DMA resource with the configurations. + * \snippet qs_usart_dma_use.c setup_tx_4 + * + * -# Create a DMA transfer descriptor configuration structure, which can be + * filled out to adjust the configuration of a single DMA transfer. + * \snippet qs_usart_dma_use.c setup_tx_5 + * + * -# Initialize the DMA transfer descriptor configuration struct with the module's + * default values. + * \snippet qs_usart_dma_use.c setup_tx_6 + * \note This should always be performed before using the configuration + * struct to ensure that all values are initialized to known default + * settings. + * + * -# Set the specific parameters for a DMA transfer with transfer size, source + * address, and destination address. + * \snippet qs_usart_dma_use.c setup_tx_7 + * + * -# Create the DMA transfer descriptor. + * \snippet qs_usart_dma_use.c setup_tx_8 + * + * \section asfdoc_sam0_usart_dma_use_case_main Use Case + * + * \subsection asfdoc_sam0_usart_dma_use_case_main_code Code + * Copy-paste the following code to your user application: + * \snippet qs_usart_dma_use.c main + * + * \subsection asfdoc_sam0_usart_dma_use_case_main_flow Workflow + * -# Wait for receiving data. + * \snippet qs_usart_dma_use.c main_1 + * + * -# Enter endless loop. + * \snippet qs_usart_dma_use.c endless_loop + */ diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/usart/quick_start_lin/qs_lin.h b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/usart/quick_start_lin/qs_lin.h new file mode 100644 index 000000000..0a59d0630 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/usart/quick_start_lin/qs_lin.h @@ -0,0 +1,94 @@ +/** + * \file + * + * \brief SAM USART LIN Quick Start + * + * Copyright (c) 2015-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ + +/** + * \page asfdoc_sam0_sercom_usart_lin_use_case Quick Start Guide for SERCOM USART LIN + * + * The supported board list: + * - SAMC21 Xplained Pro + * + * This quick start will set up LIN frame format transmission according to your + * configuration \c CONF_LIN_NODE_TYPE. + * For LIN master, it will send LIN command after startup. + * For LIN salve, once received a format from LIN master with ID \c LIN_ID_FIELD_VALUE, + * it will reply four data bytes plus a checksum. + * + * \section asfdoc_sam0_sercom_usart_lin_use_case_setup Setup + * + * \subsection asfdoc_sam0_sercom_usart_lin_use_case_prereq Prerequisites + * When verify data transmission between LIN master and slave, two boards are needed: + * one is for LIN master and the other is for LIN slave. + * connect LIN master LIN PIN with LIN slave LIN PIN. + * + * \subsection asfdoc_sam0_usart_lin_use_case_setup_code Code + * Add to the main application source file, outside of any functions: + * \snippet qs_lin.c module_var + * + * Copy-paste the following setup code to your user application: + * \snippet qs_lin.c setup + * + * Add to user application initialization (typically the start of \c main()): + * \snippet qs_lin.c setup_init + * + * \subsection asfdoc_sam0_usart_lin_use_case_setup_flow Workflow + * -# Create USART CDC and LIN module software instance structure for the USART module to store + * the USART driver state while it is in use. + * \snippet qs_lin.c module_inst + * -# Define LIN ID field for header format. + * \snippet qs_lin.c lin_id + * \note The ID \c LIN_ID_FIELD_VALUE is eight bits as [P1,P0,ID5...ID0], when it's 0x64, the + * data field length is four bytes plus a checksum byte. + * + * -# Define LIN RX/TX buffer. + * \snippet qs_lin.c lin_buffer + * \note For \c tx_buffer and \c rx_buffer, the last byte is for checksum. + * + * -# Configure the USART CDC for output message. + * \snippet qs_lin.c CDC_setup + * + * -# Configure the USART LIN module. + * \snippet qs_lin.c lin_setup + * \note The LIN frame format can be configured as master or slave, refer to \c CONF_LIN_NODE_TYPE . + * + * \section asfdoc_sam0_usart_lin_use_case_main Use Case + * + * \subsection asfdoc_sam0_usart_lin_use_case_main_code Code + * Copy-paste the following code to your user application: + * \snippet qs_lin.c main_setup + * + * \subsection asfdoc_sam0_usart_lin_use_case_main_flow Workflow + * -# Set up USART LIN module. + * \snippet qs_lin.c configure_lin + * -# For LIN master, sending LIN command. For LIN slaver, start reading data . + * \snippet qs_lin.c lin_master_cmd + */ diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/usart/usart.c b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/usart/usart.c new file mode 100644 index 000000000..468442004 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/usart/usart.c @@ -0,0 +1,806 @@ +/** + * \file + * + * \brief SAM SERCOM USART Driver + * + * Copyright (c) 2012-2020 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#include "usart.h" +#include +#if USART_CALLBACK_MODE == true +# include "usart_interrupt.h" +#endif + +/** + * \internal + * Set Configuration of the USART module + */ +static enum status_code _usart_set_config( + struct usart_module *const module, + const struct usart_config *const config) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + /* Get a pointer to the hardware module instance */ + SercomUsart *const usart_hw = &(module->hw->USART); + + /* Index for generic clock */ + uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw); + uint32_t gclk_index; + +#if (SAML21) || (SAMR30) || (SAMR34) || (SAMR35) || (SAMC21) || (WLR089) + if (sercom_index == 5) { + gclk_index = SERCOM5_GCLK_ID_CORE; + } else { + gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; + } +#else + gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; +#endif + + /* Cache new register values to minimize the number of register writes */ + uint32_t ctrla = 0; + uint32_t ctrlb = 0; +#ifdef FEATURE_USART_ISO7816 + uint32_t ctrlc = 0; +#endif + uint16_t baud = 0; + uint32_t transfer_mode; + + enum sercom_asynchronous_operation_mode mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC; + enum sercom_asynchronous_sample_num sample_num = SERCOM_ASYNC_SAMPLE_NUM_16; + +#ifdef FEATURE_USART_OVER_SAMPLE + switch (config->sample_rate) { + case USART_SAMPLE_RATE_16X_ARITHMETIC: + mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC; + sample_num = SERCOM_ASYNC_SAMPLE_NUM_16; + break; + case USART_SAMPLE_RATE_8X_ARITHMETIC: + mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC; + sample_num = SERCOM_ASYNC_SAMPLE_NUM_8; + break; + case USART_SAMPLE_RATE_3X_ARITHMETIC: + mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC; + sample_num = SERCOM_ASYNC_SAMPLE_NUM_3; + break; + case USART_SAMPLE_RATE_16X_FRACTIONAL: + mode = SERCOM_ASYNC_OPERATION_MODE_FRACTIONAL; + sample_num = SERCOM_ASYNC_SAMPLE_NUM_16; + break; + case USART_SAMPLE_RATE_8X_FRACTIONAL: + mode = SERCOM_ASYNC_OPERATION_MODE_FRACTIONAL; + sample_num = SERCOM_ASYNC_SAMPLE_NUM_8; + break; + } +#endif + + /* Set data order, internal muxing, and clock polarity */ + ctrla = (uint32_t)config->data_order | + (uint32_t)config->mux_setting | + #ifdef FEATURE_USART_OVER_SAMPLE + config->sample_adjustment | + config->sample_rate | + #endif + #ifdef FEATURE_USART_IMMEDIATE_BUFFER_OVERFLOW_NOTIFICATION + (config->immediate_buffer_overflow_notification << SERCOM_USART_CTRLA_IBON_Pos) | + #endif + (config->clock_polarity_inverted << SERCOM_USART_CTRLA_CPOL_Pos); + + enum status_code status_code = STATUS_OK; + + transfer_mode = (uint32_t)config->transfer_mode; +#ifdef FEATURE_USART_ISO7816 + if(config->iso7816_config.enabled) { + transfer_mode = config->iso7816_config.protocol_t; + } +#endif + /* Get baud value from mode and clock */ +#ifdef FEATURE_USART_ISO7816 + if(config->iso7816_config.enabled) { + baud = config->baudrate; + } else { +#endif + switch (transfer_mode) + { + case USART_TRANSFER_SYNCHRONOUSLY: + if (!config->use_external_clock) { + status_code = _sercom_get_sync_baud_val(config->baudrate, + system_gclk_chan_get_hz(gclk_index), &baud); + } + + break; + + case USART_TRANSFER_ASYNCHRONOUSLY: + if (config->use_external_clock) { + status_code = + _sercom_get_async_baud_val(config->baudrate, + config->ext_clock_freq, &baud, mode, sample_num); + } else { + status_code = + _sercom_get_async_baud_val(config->baudrate, + system_gclk_chan_get_hz(gclk_index), &baud, mode, sample_num); + } + + break; + } + + /* Check if calculating the baudrate failed */ + if (status_code != STATUS_OK) { + /* Abort */ + return status_code; + } +#ifdef FEATURE_USART_ISO7816 + } +#endif + +#ifdef FEATURE_USART_IRDA + if(config->encoding_format_enable) { + usart_hw->RXPL.reg = config->receive_pulse_length; + } +#endif + + /*Set baud val */ + usart_hw->BAUD.reg = baud; + + /* Set sample mode */ + ctrla |= transfer_mode; + + if (config->use_external_clock == false) { + ctrla |= SERCOM_USART_CTRLA_MODE(0x1); + } + else { + ctrla |= SERCOM_USART_CTRLA_MODE(0x0); + } + + /* Set stopbits and enable transceivers */ + ctrlb = + #ifdef FEATURE_USART_IRDA + (config->encoding_format_enable << SERCOM_USART_CTRLB_ENC_Pos) | + #endif + #ifdef FEATURE_USART_START_FRAME_DECTION + (config->start_frame_detection_enable << SERCOM_USART_CTRLB_SFDE_Pos) | + #endif + #ifdef FEATURE_USART_COLLISION_DECTION + (config->collision_detection_enable << SERCOM_USART_CTRLB_COLDEN_Pos) | + #endif + (config->receiver_enable << SERCOM_USART_CTRLB_RXEN_Pos) | + (config->transmitter_enable << SERCOM_USART_CTRLB_TXEN_Pos); + +#ifdef FEATURE_USART_ISO7816 + if(config->iso7816_config.enabled) { + ctrla |= SERCOM_USART_CTRLA_FORM(0x07); + if (config->iso7816_config.enable_inverse) { + ctrla |= SERCOM_USART_CTRLA_TXINV | SERCOM_USART_CTRLA_RXINV; + } + ctrlb |= USART_CHARACTER_SIZE_8BIT; + + switch(config->iso7816_config.protocol_t) { + case ISO7816_PROTOCOL_T_0: + ctrlb |= (uint32_t)config->stopbits; + ctrlc |= SERCOM_USART_CTRLC_GTIME(config->iso7816_config.guard_time) | \ + (config->iso7816_config.inhibit_nack) | \ + (config->iso7816_config.successive_recv_nack) | \ + SERCOM_USART_CTRLC_MAXITER(config->iso7816_config.max_iterations); + break; + case ISO7816_PROTOCOL_T_1: + ctrlb |= USART_STOPBITS_1; + break; + } + } else { +#endif + ctrlb |= (uint32_t)config->stopbits; + ctrlb |= (uint32_t)config->character_size; + /* Check parity mode bits */ + if (config->parity != USART_PARITY_NONE) { + ctrla |= SERCOM_USART_CTRLA_FORM(1); + ctrlb |= config->parity; + } else { +#ifdef FEATURE_USART_LIN_SLAVE + if(config->lin_slave_enable) { + ctrla |= SERCOM_USART_CTRLA_FORM(0x4); + } else { + ctrla |= SERCOM_USART_CTRLA_FORM(0); + } +#else + ctrla |= SERCOM_USART_CTRLA_FORM(0); +#endif + } +#ifdef FEATURE_USART_ISO7816 + } +#endif + +#ifdef FEATURE_USART_LIN_MASTER + usart_hw->CTRLC.reg = ((usart_hw->CTRLC.reg) & SERCOM_USART_CTRLC_GTIME_Msk) + | config->lin_header_delay + | config->lin_break_length; + + if (config->lin_node != LIN_INVALID_MODE) { + ctrla &= ~(SERCOM_USART_CTRLA_FORM(0xf)); + ctrla |= config->lin_node; + } +#endif + + /* Set whether module should run in standby. */ + if (config->run_in_standby || system_is_debugger_present()) { + ctrla |= SERCOM_USART_CTRLA_RUNSTDBY; + } + + /* Wait until synchronization is complete */ + _usart_wait_for_sync(module); + + /* Write configuration to CTRLB */ + usart_hw->CTRLB.reg = ctrlb; + + /* Wait until synchronization is complete */ + _usart_wait_for_sync(module); + + /* Write configuration to CTRLA */ + usart_hw->CTRLA.reg = ctrla; + +#ifdef FEATURE_USART_RS485 + if ((usart_hw->CTRLA.reg & SERCOM_USART_CTRLA_FORM_Msk) != \ + SERCOM_USART_CTRLA_FORM(0x07)) { + usart_hw->CTRLC.reg &= ~(SERCOM_USART_CTRLC_GTIME(0x7)); + usart_hw->CTRLC.reg |= SERCOM_USART_CTRLC_GTIME(config->rs485_guard_time); + } +#endif + +#ifdef FEATURE_USART_ISO7816 + if(config->iso7816_config.enabled) { + _usart_wait_for_sync(module); + usart_hw->CTRLC.reg = ctrlc; + } +#endif + + return STATUS_OK; +} + +/** + * \brief Initializes the device + * + * Initializes the USART device based on the setting specified in the + * configuration struct. + * + * \param[out] module Pointer to USART device + * \param[in] hw Pointer to USART hardware instance + * \param[in] config Pointer to configuration struct + * + * \return Status of the initialization. + * + * \retval STATUS_OK The initialization was successful + * \retval STATUS_BUSY The USART module is busy + * resetting + * \retval STATUS_ERR_DENIED The USART has not been disabled in + * advance of initialization + * \retval STATUS_ERR_INVALID_ARG The configuration struct contains + * invalid configuration + * \retval STATUS_ERR_ALREADY_INITIALIZED The SERCOM instance has already been + * initialized with different clock + * configuration + * \retval STATUS_ERR_BAUD_UNAVAILABLE The BAUD rate given by the + * configuration + * struct cannot be reached with + * the current clock configuration + */ +enum status_code usart_init( + struct usart_module *const module, + Sercom *const hw, + const struct usart_config *const config) +{ + /* Sanity check arguments */ + Assert(module); + Assert(hw); + Assert(config); + + enum status_code status_code = STATUS_OK; + + /* Assign module pointer to software instance struct */ + module->hw = hw; + + /* Get a pointer to the hardware module instance */ + SercomUsart *const usart_hw = &(module->hw->USART); + + uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw); + uint32_t pm_index, gclk_index; +#if (SAML22) || (SAMC20) + pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos; + gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; +#elif (SAML21) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + if (sercom_index == 5) { + pm_index = MCLK_APBDMASK_SERCOM5_Pos; + gclk_index = SERCOM5_GCLK_ID_CORE; + } else { + pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos; + gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; + } +#elif (SAMC21) + pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos; + + if (sercom_index == 5){ + gclk_index = SERCOM5_GCLK_ID_CORE; + } else { + gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; + } +#else + pm_index = sercom_index + PM_APBCMASK_SERCOM0_Pos; + gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; +#endif + + if (usart_hw->CTRLA.reg & SERCOM_USART_CTRLA_SWRST) { + /* The module is busy resetting itself */ + return STATUS_BUSY; + } + + if (usart_hw->CTRLA.reg & SERCOM_USART_CTRLA_ENABLE) { + /* Check the module is enabled */ + return STATUS_ERR_DENIED; + } + + /* Turn on module in PM */ +#if (SAML21) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + if (sercom_index == 5) { + system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBD, 1 << pm_index); + } else { + system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index); + } +#else + system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index); +#endif + + /* Set up the GCLK for the module */ + struct system_gclk_chan_config gclk_chan_conf; + system_gclk_chan_get_config_defaults(&gclk_chan_conf); + gclk_chan_conf.source_generator = config->generator_source; + system_gclk_chan_set_config(gclk_index, &gclk_chan_conf); + system_gclk_chan_enable(gclk_index); + sercom_set_gclk_generator(config->generator_source, false); + + /* Set character size */ + module->character_size = config->character_size; + + /* Set transmitter and receiver status */ + module->receiver_enabled = config->receiver_enable; + module->transmitter_enabled = config->transmitter_enable; + +#ifdef FEATURE_USART_LIN_SLAVE + module->lin_slave_enabled = config->lin_slave_enable; +#endif +#ifdef FEATURE_USART_START_FRAME_DECTION + module->start_frame_detection_enabled = config->start_frame_detection_enable; +#endif +#ifdef FEATURE_USART_ISO7816 + module->iso7816_mode_enabled = config->iso7816_config.enabled; +#endif + /* Set configuration according to the config struct */ + status_code = _usart_set_config(module, config); + if(status_code != STATUS_OK) { + return status_code; + } + + struct system_pinmux_config pin_conf; + system_pinmux_get_config_defaults(&pin_conf); + pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT; + pin_conf.input_pull = SYSTEM_PINMUX_PIN_PULL_NONE; + + uint32_t pad_pinmuxes[] = { + config->pinmux_pad0, config->pinmux_pad1, + config->pinmux_pad2, config->pinmux_pad3 + }; + + /* Configure the SERCOM pins according to the user configuration */ + for (uint8_t pad = 0; pad < 4; pad++) { + uint32_t current_pinmux = pad_pinmuxes[pad]; + + if (current_pinmux == PINMUX_DEFAULT) { + current_pinmux = _sercom_get_default_pad(hw, pad); + } + + if (current_pinmux != PINMUX_UNUSED) { + pin_conf.mux_position = current_pinmux & 0xFFFF; + system_pinmux_pin_set_config(current_pinmux >> 16, &pin_conf); + } + } + +#if USART_CALLBACK_MODE == true + /* Initialize parameters */ + for (uint32_t i = 0; i < USART_CALLBACK_N; i++) { + module->callback[i] = NULL; + } + + module->tx_buffer_ptr = NULL; + module->rx_buffer_ptr = NULL; + module->remaining_tx_buffer_length = 0x0000; + module->remaining_rx_buffer_length = 0x0000; + module->callback_reg_mask = 0x00; + module->callback_enable_mask = 0x00; + module->rx_status = STATUS_OK; + module->tx_status = STATUS_OK; + + /* Set interrupt handler and register USART software module struct in + * look-up table */ + uint8_t instance_index = _sercom_get_sercom_inst_index(module->hw); + _sercom_set_handler(instance_index, _usart_interrupt_handler); + _sercom_instances[instance_index] = module; +#endif + + return status_code; +} + +/** + * \brief Transmit a character via the USART + * + * This blocking function will transmit a single character via the + * USART. + * + * \param[in] module Pointer to the software instance struct + * \param[in] tx_data Data to transfer + * + * \return Status of the operation. + * \retval STATUS_OK If the operation was completed + * \retval STATUS_BUSY If the operation was not completed, due to the USART + * module being busy + * \retval STATUS_ERR_DENIED If the transmitter is not enabled + */ +enum status_code usart_write_wait( + struct usart_module *const module, + const uint16_t tx_data) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + /* Get a pointer to the hardware module instance */ + SercomUsart *const usart_hw = &(module->hw->USART); + + /* Check that the transmitter is enabled */ + if (!(module->transmitter_enabled)) { + return STATUS_ERR_DENIED; + } + +#if USART_CALLBACK_MODE == true + /* Check if the USART is busy doing asynchronous operation. */ + if (module->remaining_tx_buffer_length > 0) { + return STATUS_BUSY; + } + +#else + /* Check if USART is ready for new data */ + if (!(usart_hw->INTFLAG.reg & SERCOM_USART_INTFLAG_DRE)) { + /* Return error code */ + return STATUS_BUSY; + } +#endif + + /* Write data to USART module */ + usart_hw->DATA.reg = tx_data; + + while (!(usart_hw->INTFLAG.reg & SERCOM_USART_INTFLAG_TXC)) { + /* Wait until data is sent */ + } + + return STATUS_OK; +} + +/** + * \brief Receive a character via the USART + * + * This blocking function will receive a character via the USART. + * + * \param[in] module Pointer to the software instance struct + * \param[out] rx_data Pointer to received data + * + * \return Status of the operation. + * \retval STATUS_OK If the operation was completed + * \retval STATUS_BUSY If the operation was not completed, + * due to the USART module being busy + * \retval STATUS_ERR_BAD_FORMAT If the operation was not completed, + * due to configuration mismatch between USART + * and the sender + * \retval STATUS_ERR_BAD_OVERFLOW If the operation was not completed, + * due to the baudrate being too low or the + * system frequency being too high + * \retval STATUS_ERR_BAD_DATA If the operation was not completed, due to + * data being corrupted + * \retval STATUS_ERR_DENIED If the receiver is not enabled + */ +enum status_code usart_read_wait( + struct usart_module *const module, + uint16_t *const rx_data) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + /* Error variable */ + uint8_t error_code; + + /* Get a pointer to the hardware module instance */ + SercomUsart *const usart_hw = &(module->hw->USART); + + /* Check that the receiver is enabled */ + if (!(module->receiver_enabled)) { + return STATUS_ERR_DENIED; + } + +#if USART_CALLBACK_MODE == true + /* Check if the USART is busy doing asynchronous operation. */ + if (module->remaining_rx_buffer_length > 0) { + return STATUS_BUSY; + } +#endif + + /* Check if USART has new data */ + if (!(usart_hw->INTFLAG.reg & SERCOM_USART_INTFLAG_RXC)) { + /* Return error code */ + return STATUS_BUSY; + } + + /* Read out the status code and mask away all but the 3 LSBs*/ + error_code = (uint8_t)(usart_hw->STATUS.reg & SERCOM_USART_STATUS_MASK); + + /* Check if an error has occurred during the receiving */ + if (error_code) { + /* Check which error occurred */ + if (error_code & SERCOM_USART_STATUS_FERR) { + /* Clear flag by writing a 1 to it and + * return with an error code */ + usart_hw->STATUS.reg = SERCOM_USART_STATUS_FERR; + + return STATUS_ERR_BAD_FORMAT; + } else if (error_code & SERCOM_USART_STATUS_BUFOVF) { + /* Clear flag by writing a 1 to it and + * return with an error code */ + usart_hw->STATUS.reg = SERCOM_USART_STATUS_BUFOVF; + + return STATUS_ERR_OVERFLOW; + } else if (error_code & SERCOM_USART_STATUS_PERR) { + /* Clear flag by writing a 1 to it and + * return with an error code */ + usart_hw->STATUS.reg = SERCOM_USART_STATUS_PERR; + + return STATUS_ERR_BAD_DATA; + } +#ifdef FEATURE_USART_LIN_SLAVE + else if (error_code & SERCOM_USART_STATUS_ISF) { + /* Clear flag by writing 1 to it and + * return with an error code */ + usart_hw->STATUS.reg = SERCOM_USART_STATUS_ISF; + + return STATUS_ERR_PROTOCOL; + } +#endif +#ifdef FEATURE_USART_COLLISION_DECTION + else if (error_code & SERCOM_USART_STATUS_COLL) { + /* Clear flag by writing 1 to it + * return with an error code */ + usart_hw->STATUS.reg = SERCOM_USART_STATUS_COLL; + + return STATUS_ERR_PACKET_COLLISION; + } +#endif + } + + /* Read data from USART module */ + *rx_data = usart_hw->DATA.reg; + + return STATUS_OK; +} + +/** + * \brief Transmit a buffer of characters via the USART + * + * This blocking function will transmit a block of \c length characters + * via the USART. + * + * \note Using this function in combination with the interrupt (\c _job) functions is + * not recommended as it has no functionality to check if there is an + * ongoing interrupt driven operation running or not. + * + * \param[in] module Pointer to USART software instance struct + * \param[in] tx_data Pointer to data to transmit + * \param[in] length Number of characters to transmit + * + * \note If using 9-bit data, the array that *tx_data point to should be defined + * as uint16_t array and should be casted to uint8_t* pointer. Because it + * is an address pointer, the highest byte is not discarded. For example: + * \code + #define TX_LEN 3 + uint16_t tx_buf[TX_LEN] = {0x0111, 0x0022, 0x0133}; + usart_write_buffer_wait(&module, (uint8_t*)tx_buf, TX_LEN); + \endcode + * + * \return Status of the operation. + * \retval STATUS_OK If operation was completed + * \retval STATUS_ERR_INVALID_ARG If operation was not completed, due to invalid + * arguments + * \retval STATUS_ERR_TIMEOUT If operation was not completed, due to USART + * module timing out + * \retval STATUS_ERR_DENIED If the transmitter is not enabled + */ +enum status_code usart_write_buffer_wait( + struct usart_module *const module, + const uint8_t *tx_data, + uint16_t length) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + /* Check if the buffer length is valid */ + if (length == 0) { + return STATUS_ERR_INVALID_ARG; + } + + /* Check that the transmitter is enabled */ + if (!(module->transmitter_enabled)) { + return STATUS_ERR_DENIED; + } + + /* Get a pointer to the hardware module instance */ + SercomUsart *const usart_hw = &(module->hw->USART); + + uint16_t tx_pos = 0; + + /* Blocks while buffer is being transferred */ + while (length--) { + /* Wait for the USART to be ready for new data and abort + * operation if it doesn't get ready within the timeout*/ + for (uint32_t i = 0; i <= USART_TIMEOUT; i++) { + if (usart_hw->INTFLAG.reg & SERCOM_USART_INTFLAG_DRE) { + break; + } else if (i == USART_TIMEOUT) { + return STATUS_ERR_TIMEOUT; + } + } + + /* Data to send is at least 8 bits long */ + uint16_t data_to_send = tx_data[tx_pos++]; + + /* Check if the character size exceeds 8 bit */ + if (module->character_size == USART_CHARACTER_SIZE_9BIT) { + data_to_send |= (tx_data[tx_pos++] << 8); + } + + /* Send the data through the USART module */ + usart_write_wait(module, data_to_send); + } + + /* Wait until Transmit is complete or timeout */ + for (uint32_t i = 0; i <= USART_TIMEOUT; i++) { + if (usart_hw->INTFLAG.reg & SERCOM_USART_INTFLAG_TXC) { + break; + } else if (i == USART_TIMEOUT) { + return STATUS_ERR_TIMEOUT; + } + } + + return STATUS_OK; +} + +/** + * \brief Receive a buffer of \c length characters via the USART + * + * This blocking function will receive a block of \c length characters + * via the USART. + * + * \note Using this function in combination with the interrupt (\c *_job) + * functions is not recommended as it has no functionality to check if + * there is an ongoing interrupt driven operation running or not. + * + * \param[in] module Pointer to USART software instance struct + * \param[out] rx_data Pointer to receive buffer + * \param[in] length Number of characters to receive + * + * \note If using 9-bit data, the array that *rx_data point to should be defined + * as uint16_t array and should be casted to uint8_t* pointer. Because it + * is an address pointer, the highest byte is not discarded. For example: + * \code + #define RX_LEN 3 + uint16_t rx_buf[RX_LEN] = {0x0,}; + usart_read_buffer_wait(&module, (uint8_t*)rx_buf, RX_LEN); + \endcode + * + * \return Status of the operation. + * \retval STATUS_OK If operation was completed + * \retval STATUS_ERR_INVALID_ARG If operation was not completed, due to an + * invalid argument being supplied + * \retval STATUS_ERR_TIMEOUT If operation was not completed, due + * to USART module timing out + * \retval STATUS_ERR_BAD_FORMAT If the operation was not completed, + * due to a configuration mismatch + * between USART and the sender + * \retval STATUS_ERR_BAD_OVERFLOW If the operation was not completed, + * due to the baudrate being too low or the + * system frequency being too high + * \retval STATUS_ERR_BAD_DATA If the operation was not completed, due + * to data being corrupted + * \retval STATUS_ERR_DENIED If the receiver is not enabled + */ +enum status_code usart_read_buffer_wait( + struct usart_module *const module, + uint8_t *rx_data, + uint16_t length) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + /* Check if the buffer length is valid */ + if (length == 0) { + return STATUS_ERR_INVALID_ARG; + } + + /* Check that the receiver is enabled */ + if (!(module->receiver_enabled)) { + return STATUS_ERR_DENIED; + } + + /* Get a pointer to the hardware module instance */ + SercomUsart *const usart_hw = &(module->hw->USART); + + uint16_t rx_pos = 0; + + /* Blocks while buffer is being received */ + while (length--) { + /* Wait for the USART to have new data and abort operation if it + * doesn't get ready within the timeout*/ + for (uint32_t i = 0; i <= USART_TIMEOUT; i++) { + if (usart_hw->INTFLAG.reg & SERCOM_USART_INTFLAG_RXC) { + break; + } else if (i == USART_TIMEOUT) { + return STATUS_ERR_TIMEOUT; + } + } + + enum status_code retval; + uint16_t received_data = 0; + + retval = usart_read_wait(module, &received_data); + + if (retval != STATUS_OK) { + /* Overflow, abort */ + return retval; + } + + /* Read value will be at least 8-bits long */ + rx_data[rx_pos++] = received_data; + + /* If 9-bit data, write next received byte to the buffer */ + if (module->character_size == USART_CHARACTER_SIZE_9BIT) { + rx_data[rx_pos++] = (received_data >> 8); + } + } + + return STATUS_OK; +} diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/usart/usart.h b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/usart/usart.h new file mode 100644 index 000000000..6f5ca9598 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/usart/usart.h @@ -0,0 +1,1589 @@ +/** + * + * \file + * + * \brief SAM SERCOM USART Driver + * + * Copyright (c) 2012-2020 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#ifndef USART_H_INCLUDED +#define USART_H_INCLUDED + +/** + * \defgroup asfdoc_sam0_sercom_usart_group SAM Serial USART (SERCOM USART) Driver + * + * This driver for Atmel® | SMART ARM®-based microcontrollers provides + * an interface for the configuration and management of the SERCOM module in + * its USART mode to transfer or receive USART data frames. The following driver + * API modes are covered by this manual: + * + * - Polled APIs + * \if USART_CALLBACK_MODE + * - Callback APIs + * \endif + * + * The following peripheral is used by this module: + * - SERCOM (Serial Communication Interface) + * + * The following devices can use this module: + * - Atmel | SMART SAM D20/D21 + * - Atmel | SMART SAM R21 + * - Atmel | SMART SAM D09/D10/D11 + * - Atmel | SMART SAM D10/D11 + * - Atmel | SMART SAM L21/L22 + * - Atmel | SMART SAM DA1 + * - Atmel | SMART SAM C20/C21 + * - Atmel | SMART SAM HA1 + * - Atmel | SMART SAM R30 + * - Atmel | SMART SAM R34 + * - Atmel | SMART SAM R35 + * + * The outline of this documentation is as follows: + * - \ref asfdoc_sam0_sercom_usart_prerequisites + * - \ref asfdoc_sam0_sercom_usart_overview + * - \ref asfdoc_sam0_sercom_usart_special_considerations + * - \ref asfdoc_sam0_sercom_usart_extra_info + * - \ref asfdoc_sam0_sercom_usart_examples + * - \ref asfdoc_sam0_sercom_usart_api_overview + * + * \section asfdoc_sam0_sercom_usart_prerequisites Prerequisites + * + * To use the USART you need to have a GCLK generator enabled and running + * that can be used as the SERCOM clock source. This can either be configured + * in conf_clocks.h or by using the system clock driver. + * + * \section asfdoc_sam0_sercom_usart_overview Module Overview + * + * This driver will use one (or more) SERCOM interface(s) in the system + * and configure it to run as a USART interface in either synchronous + * or asynchronous mode. + * + * \subsection asfdoc_sam0_sercom_usart_features Driver Feature Macro Definition + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Driver Feature MacroSupported devices
FEATURE_USART_SYNC_SCHEME_V2SAM D21/R21/D09/D10/D11/L21/L22/DA1/C20/C21/R30/R34/R35
FEATURE_USART_OVER_SAMPLESAM D21/R21/D09/D10/D11/L21/L22/DA1/C20/C21/R30/R34/R35
FEATURE_USART_HARDWARE_FLOW_CONTROLSAM D21/R21/D09/D10/D11/L21/L22/DA1/C20/C21/R30/R34/R35
FEATURE_USART_IRDASAM D21/R21/D09/D10/D11/L21/L22/DA1/C20/C21/R30/R34/R35
FEATURE_USART_LIN_SLAVESAM D21/R21/D09/D10/D11/L21/L22/DA1/C20/C21/R30/R34/R35
FEATURE_USART_COLLISION_DECTIONSAM D21/R21/D09/D10/D11/L21/L22/DA1/C20/C21/R30/R34/R35
FEATURE_USART_START_FRAME_DECTIONSAM D21/R21/D09/D10/D11/L21/L22/DA1/C20/C21/R30/R34/R35
FEATURE_USART_IMMEDIATE_BUFFER_OVERFLOW_NOTIFICATIONSAM D21/R21/D09/D10/D11/L21/L22/DA1/C20/C21/R30/R34/R35
FEATURE_USART_RS485SAM C20/C21
FEATURE_USART_LIN_MASTERSAM L22/C20/C21
+ * \note The specific features are only available in the driver when the + * selected device supports those features. + * + * \subsection asfdoc_sam0_sercom_usart_overview_frame_format Frame Format + * + * Communication is based on frames, where the frame format can be customized + * to accommodate a wide range of standards. A frame consists of a start bit, + * a number of data bits, an optional parity bit for error detection as well + * as a configurable length stop bit(s) - see + * \ref asfdoc_sam0_sercom_usart_frame_diagram "the figure below". + * \ref asfdoc_sam0_sercom_usart_frame_params "The table below" shows the + * available parameters you can change in a frame. + * + * \anchor asfdoc_sam0_sercom_usart_frame_params + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
USART Frame Parameters
ParameterOptions
Start bit1
Data bits5, 6, 7, 8, 9
Parity bitNone, Even, Odd
Stop bits1, 2
+ * + * \anchor asfdoc_sam0_sercom_usart_frame_diagram + * \image html usart_frame.svg "USART Frame Overview" width=100% + * + * \subsection asfdoc_sam0_sercom_usart_overview_sync Synchronous Mode + * + * In synchronous mode a dedicated clock line is provided; either by the USART + * itself if in master mode, or by an external master if in slave mode. + * Maximum transmission speed is the same as the GCLK clocking the USART + * peripheral when in slave mode, and the GCLK divided by two if in + * master mode. In synchronous mode the interface needs three lines to + * communicate: + * - TX (Transmit pin) + * - RX (Receive pin) + * - XCK (Clock pin) + * + * \subsubsection asfdoc_sam0_sercom_usart_overview_sync_sampling Data Sampling + * In synchronous mode the data is sampled on either the rising or falling edge + * of the clock signal. This is configured by setting the clock polarity in the + * configuration struct. + * + * \subsection asfdoc_sam0_sercom_usart_overview_async Asynchronous Mode + * + * In asynchronous mode no dedicated clock line is used, and the communication + * is based on matching the clock speed on the transmitter and receiver. The + * clock is generated from the internal SERCOM baudrate generator, and the + * frames are synchronized by using the frame start bits. Maximum transmission + * speed is limited to the SERCOM GCLK divided by 16. + * In asynchronous mode the interface only needs two lines to communicate: + * - TX (Transmit pin) + * - RX (Receive pin) + * + * \subsubsection asfdoc_sam0_sercom_usart_overview_async_clock_matching Transmitter/receiver Clock Matching + * + * For successful transmit and receive using the asynchronous mode the receiver + * and transmitter clocks needs to be closely matched. When receiving a frame + * that does not match the selected baudrate closely enough the receiver will + * be unable to synchronize the frame(s), and garbage transmissions will + * result. + * + * \subsection asfdoc_sam0_sercom_usart_parity Parity + * Parity can be enabled to detect if a transmission was in error. This is done + * by counting the number of "1" bits in the frame. When using even parity the + * parity bit will be set if the total number of "1"s in the frame are an even + * number. If using odd parity the parity bit will be set if the total number + * of "1"s are odd. + * + * When receiving a character the receiver will count the number of "1"s in the + * frame and give an error if the received frame and parity bit disagree. + * + * \subsection asfdoc_sam0_sercom_usart_overview_pin_configuration GPIO Configuration + * + * The SERCOM module has four internal pads; the RX pin can be placed freely on + * any one of the four pads, and the TX and XCK pins have two predefined + * positions that can be selected as a pair. The pads can then be routed to an + * external GPIO pin using the normal pin multiplexing scheme on the SAM. + * + * \section asfdoc_sam0_sercom_usart_special_considerations Special Considerations + * + * \if USART_CALLBACK_MODE + * Never execute large portions of code in the callbacks. These + * are run from the interrupt routine, and thus having long callbacks will + * keep the processor in the interrupt handler for an equally long time. + * A common way to handle this is to use global flags signaling the + * main application that an interrupt event has happened, and only do the + * minimal needed processing in the callback. + * \else + * No special considerations. + * \endif + * + * \section asfdoc_sam0_sercom_usart_extra_info Extra Information + * + * For extra information, see \ref asfdoc_sam0_sercom_usart_extra. This includes: + * - \ref asfdoc_sam0_sercom_usart_extra_acronyms + * - \ref asfdoc_sam0_sercom_usart_extra_dependencies + * - \ref asfdoc_sam0_sercom_usart_extra_errata + * - \ref asfdoc_sam0_sercom_usart_extra_history + * + * \section asfdoc_sam0_sercom_usart_examples Examples + * + * For a list of examples related to this driver, see + * \ref asfdoc_sam0_sercom_usart_exqsg. + * + * \section asfdoc_sam0_sercom_usart_api_overview API Overview + * @{ + */ + +#include +#include +#include + +#if USART_CALLBACK_MODE == true +# include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \name Driver Feature Definition + * Define SERCOM USART features set according to different device family. + * @{ + */ + +#if (SAMD21) || (SAMR21) || (SAMD09) || (SAMD10) || (SAMD11) || \ + (SAML21) || (SAML22) || (SAMDA1) || (SAMC20) || (SAMC21) || \ + (SAMR30) || (SAMHA1) || (SAMHA0) || (SAMR34) || (SAMR35) || (WLR089) || defined(__DOXYGEN__) +/** USART sync scheme version 2. */ +# define FEATURE_USART_SYNC_SCHEME_V2 +/** USART oversampling. */ +# define FEATURE_USART_OVER_SAMPLE +/** USART hardware control flow. */ +# define FEATURE_USART_HARDWARE_FLOW_CONTROL +/** IrDA mode. */ +# define FEATURE_USART_IRDA +/** LIN slave mode. */ +# define FEATURE_USART_LIN_SLAVE +/** USART collision detection. */ +# define FEATURE_USART_COLLISION_DECTION +/** USART start frame detection. */ +# define FEATURE_USART_START_FRAME_DECTION +/** USART start buffer overflow notification. */ +# define FEATURE_USART_IMMEDIATE_BUFFER_OVERFLOW_NOTIFICATION +#endif + +#if (SAML22) || defined(__DOXYGEN__) +/** ISO7816 for smart card interfacing. */ +#define FEATURE_USART_ISO7816 +#endif +#if (SAMC20) || (SAMC21) || defined(__DOXYGEN__) +/** LIN master mode. */ +#define FEATURE_USART_LIN_MASTER +#endif +#if (SAML22) || (SAMC20) || (SAMC21) || defined(__DOXYGEN__) +/** RS485 mode. */ +# define FEATURE_USART_RS485 +#endif +/*@}*/ + +#ifdef FEATURE_USART_LIN_MASTER +/** + * \brief LIN node type + * + * LIN node type. + */ +enum lin_node_type { + /** LIN master mode */ + LIN_MASTER_NODE = SERCOM_USART_CTRLA_FORM(0x02), + /** LIN slave mode */ + LIN_SLAVE_NODE = SERCOM_USART_CTRLA_FORM(0x04), + /** Neither LIN master nor LIN slave mode */ + LIN_INVALID_MODE = SERCOM_USART_CTRLA_FORM(0x00), +}; + +/** + * \brief LIN master command enum + * + * LIN master command enum. + */ +enum lin_master_cmd { + /** LIN master software control transmission command */ + LIN_MASTER_SOFTWARE_CONTROL_TRANSMIT_CMD = SERCOM_USART_CTRLB_LINCMD(0x01), + /** LIN master automatically transmission command */ + LIN_MASTER_AUTO_TRANSMIT_CMD = SERCOM_USART_CTRLB_LINCMD(0x02), +}; + +/** + * \brief LIN master header delay + * + * LIN master header delay between break and sync transmission, + * and between the sync and identifier (ID) fields. + * This field is only valid when using automatically transmission command + */ +enum lin_master_header_delay { + /** Delay between break and sync transmission is 1 bit time. + Delay between sync and ID transmission is 1 bit time. */ + LIN_MASTER_HEADER_DELAY_0 = SERCOM_USART_CTRLC_HDRDLY(0x0), + /** Delay between break and sync transmission is 4 bit time. + Delay between sync and ID transmission is 4 bit time. */ + LIN_MASTER_HEADER_DELAY_1 = SERCOM_USART_CTRLC_HDRDLY(0x01), + /** Delay between break and sync transmission is 8 bit time. + Delay between sync and ID transmission is 4 bit time. */ + LIN_MASTER_HEADER_DELAY_2 = SERCOM_USART_CTRLC_HDRDLY(0x02), + /** Delay between break and sync transmission is 14 bit time. + Delay between sync and ID transmission is 4 bit time. */ + LIN_MASTER_HEADER_DELAY_3 = SERCOM_USART_CTRLC_HDRDLY(0x03), +}; + +/** + * \brief LIN master break length + * + * Length of the break field transmitted when in LIN master mode + */ +enum lin_master_break_length { + /** Break field transmission is 13 bit times */ + LIN_MASTER_BREAK_LENGTH_13_BIT = SERCOM_USART_CTRLC_BRKLEN(0x0), + /** Break field transmission is 17 bit times */ + LIN_MASTER_BREAK_LENGTH_17_BIT = SERCOM_USART_CTRLC_BRKLEN(0x1), + /** Break field transmission is 21 bit times */ + LIN_MASTER_BREAK_LENGTH_21_BIT = SERCOM_USART_CTRLC_BRKLEN(0x2), + /** Break field transmission is 26 bit times */ + LIN_MASTER_BREAK_LENGTH_26_BIT = SERCOM_USART_CTRLC_BRKLEN(0x3), +}; +#endif +#ifdef FEATURE_USART_ISO7816 +/** + * \brief ISO7816 protocol type + * + * ISO7816 protocol type. + */ +enum iso7816_protocol_type { + /** ISO7816 protocol type 0 */ + ISO7816_PROTOCOL_T_0 = SERCOM_USART_CTRLA_CMODE, + /** ISO7816 protocol type 1 */ + ISO7816_PROTOCOL_T_1 = (0x0ul << SERCOM_USART_CTRLA_CMODE_Pos), +}; + +/** + * \brief ISO7816 guard time + * + * The value of ISO7816 guard time. + */ +enum iso7816_guard_time { + /** The guard time is 2-bit times */ + ISO7816_GUARD_TIME_2_BIT = 2, + /** The guard time is 3-bit times */ + ISO7816_GUARD_TIME_3_BIT, + /** The guard time is 4-bit times */ + ISO7816_GUARD_TIME_4_BIT, + /** The guard time is 5-bit times */ + ISO7816_GUARD_TIME_5_BIT, + /** The guard time is 6-bit times */ + ISO7816_GUARD_TIME_6_BIT, + /** The guard time is 7-bit times */ + ISO7816_GUARD_TIME_7_BIT, +}; + +/** + * \brief ISO7816 receive NACK inhibit + * + * The value of ISO7816 receive NACK inhibit. + */ +enum iso7816_inhibit_nack { + /** The NACK is generated */ + ISO7816_INHIBIT_NACK_DISABLE = (0x0ul << SERCOM_USART_CTRLC_INACK_Pos), + /** The NACK is not generated */ + ISO7816_INHIBIT_NACK_ENABLE = SERCOM_USART_CTRLC_INACK, +}; + +/** + * \brief ISO7816 disable successive receive NACK + * + * The value of ISO7816 disable successive receive NACK. + */ +enum iso7816_successive_recv_nack { + /** The successive receive NACK is enable. */ + ISO7816_SUCCESSIVE_RECV_NACK_DISABLE = (0x0ul << SERCOM_USART_CTRLC_INACK_Pos), + /** The successive receive NACK is disable. */ + ISO7816_SUCCESSIVE_RECV_NACK_ENABLE = SERCOM_USART_CTRLC_DSNACK, +}; + +/** + * \brief ISO7816 configuration struct + * + * ISO7816 configuration structure. + */ +struct iso7816_config_t { + /* ISO7816 mode enable */ + bool enabled; + /** ISO7816 protocol type */ + enum iso7816_protocol_type protocol_t; + /** Enable inverse transmission and reception */ + bool enable_inverse; + /** Guard time, which lasts two bit times */ + enum iso7816_guard_time guard_time; + /** + * Inhibit Non Acknowledge: + * - 0: the NACK is generated; + * - 1: the NACK is not generated. + */ + enum iso7816_inhibit_nack inhibit_nack; + /** + * Disable successive NACKs. + * - 0: NACK is sent on the ISO line as soon as a parity error occurs + * in the received character. Successive parity errors are counted up to + * the value in the max_iterations field. These parity errors generate + * a NACK on the ISO line. As soon as this value is reached, no additional + * NACK is sent on the ISO line. The ITERATION flag is asserted. + */ + enum iso7816_successive_recv_nack successive_recv_nack; + /* Max number of repetitions */ + uint32_t max_iterations; +}; +#endif + +#ifndef PINMUX_DEFAULT +/** Default pinmux */ +# define PINMUX_DEFAULT 0 +#endif + +#ifndef PINMUX_UNUSED +/** Unused pinmux */ +# define PINMUX_UNUSED 0xFFFFFFFF +#endif + +#ifndef USART_TIMEOUT +/** USART timeout value */ +# define USART_TIMEOUT 0xFFFF +#endif + +#if USART_CALLBACK_MODE == true +/** + * \brief USART callback enum + * + * Callbacks for the Asynchronous USART driver. + */ +enum usart_callback { + /** Callback for buffer transmitted */ + USART_CALLBACK_BUFFER_TRANSMITTED, + /** Callback for buffer received */ + USART_CALLBACK_BUFFER_RECEIVED, + /** Callback for error */ + USART_CALLBACK_ERROR, +#ifdef FEATURE_USART_LIN_SLAVE + /** Callback for break character is received */ + USART_CALLBACK_BREAK_RECEIVED, +#endif +#ifdef FEATURE_USART_HARDWARE_FLOW_CONTROL + /** Callback for a change is detected on the CTS pin */ + USART_CALLBACK_CTS_INPUT_CHANGE, +#endif +#ifdef FEATURE_USART_START_FRAME_DECTION + /** Callback for a start condition is detected on the RxD line */ + USART_CALLBACK_START_RECEIVED, +#endif +# if !defined(__DOXYGEN__) + /** Number of available callbacks */ + USART_CALLBACK_N, +# endif +}; +#endif + +/** + * \brief USART Data Order enum + * + * The data order decides which MSB or LSB is shifted out first when data is + * transferred. + */ +enum usart_dataorder { + /** The MSB will be shifted out first during transmission, + * and shifted in first during reception */ + USART_DATAORDER_MSB = 0, + /** The LSB will be shifted out first during transmission, + * and shifted in first during reception */ + USART_DATAORDER_LSB = SERCOM_USART_CTRLA_DORD, +}; + +/** + * \brief USART Transfer mode enum + * + * Select USART transfer mode. + */ +enum usart_transfer_mode { + /** Transfer of data is done synchronously */ + USART_TRANSFER_SYNCHRONOUSLY = (SERCOM_USART_CTRLA_CMODE), + /** Transfer of data is done asynchronously */ + USART_TRANSFER_ASYNCHRONOUSLY = (0x0ul << SERCOM_USART_CTRLA_CMODE_Pos), +}; + +/** + * \brief USART Parity enum + * + * Select parity USART parity mode. + */ +enum usart_parity { + /** For odd parity checking, the parity bit will be set if number of + * ones being transferred is even */ + USART_PARITY_ODD = SERCOM_USART_CTRLB_PMODE, + + /** For even parity checking, the parity bit will be set if number of + * ones being received is odd */ + USART_PARITY_EVEN = 0, + + /** No parity checking will be executed, and there will be no parity bit + * in the received frame */ + USART_PARITY_NONE = 0xFF, +}; + +/** + * \brief USART signal MUX settings + * + * Set the functionality of the SERCOM pins. + * + * See \ref asfdoc_sam0_sercom_usart_mux_settings for a description of the + * various MUX setting options. + */ +enum usart_signal_mux_settings { +#ifdef FEATURE_USART_HARDWARE_FLOW_CONTROL + /** MUX setting RX_0_TX_0_XCK_1 */ + USART_RX_0_TX_0_XCK_1 = (SERCOM_USART_CTRLA_RXPO(0) | SERCOM_USART_CTRLA_TXPO(0)), + /** MUX setting RX_0_TX_2_XCK_3 */ + USART_RX_0_TX_2_XCK_3 = (SERCOM_USART_CTRLA_RXPO(0) | SERCOM_USART_CTRLA_TXPO(1)), + /** MUX setting USART_RX_0_TX_0_RTS_2_CTS_3 */ + USART_RX_0_TX_0_RTS_2_CTS_3 = (SERCOM_USART_CTRLA_RXPO(0) | SERCOM_USART_CTRLA_TXPO(2)), + /** MUX setting RX_1_TX_0_XCK_1 */ + USART_RX_1_TX_0_XCK_1 = (SERCOM_USART_CTRLA_RXPO(1) | SERCOM_USART_CTRLA_TXPO(0)), + /** MUX setting RX_1_TX_2_XCK_3 */ + USART_RX_1_TX_2_XCK_3 = (SERCOM_USART_CTRLA_RXPO(1) | SERCOM_USART_CTRLA_TXPO(1)), + /** MUX setting USART_RX_1_TX_0_RTS_2_CTS_3 */ + USART_RX_1_TX_0_RTS_2_CTS_3 = (SERCOM_USART_CTRLA_RXPO(1) | SERCOM_USART_CTRLA_TXPO(2)), + /** MUX setting RX_2_TX_0_XCK_1 */ + USART_RX_2_TX_0_XCK_1 = (SERCOM_USART_CTRLA_RXPO(2) | SERCOM_USART_CTRLA_TXPO(0)), + /** MUX setting RX_2_TX_2_XCK_3 */ + USART_RX_2_TX_2_XCK_3 = (SERCOM_USART_CTRLA_RXPO(2) | SERCOM_USART_CTRLA_TXPO(1)), + /** MUX setting USART_RX_2_TX_0_RTS_2_CTS_3 */ + USART_RX_2_TX_0_RTS_2_CTS_3 = (SERCOM_USART_CTRLA_RXPO(2) | SERCOM_USART_CTRLA_TXPO(2)), + /** MUX setting RX_3_TX_0_XCK_1 */ + USART_RX_3_TX_0_XCK_1 = (SERCOM_USART_CTRLA_RXPO(3) | SERCOM_USART_CTRLA_TXPO(0)), + /** MUX setting RX_3_TX_2_XCK_3 */ + USART_RX_3_TX_2_XCK_3 = (SERCOM_USART_CTRLA_RXPO(3) | SERCOM_USART_CTRLA_TXPO(1)), + /** MUX setting USART_RX_3_TX_0_RTS_2_CTS_3 */ + USART_RX_3_TX_0_RTS_2_CTS_3 = (SERCOM_USART_CTRLA_RXPO(3) | SERCOM_USART_CTRLA_TXPO(2)), +#ifdef FEATURE_USART_RS485 + /** MUX setting USART_RX_0_TX_0_XCK_1_TE_2 */ + USART_RX_0_TX_0_XCK_1_TE_2 = (SERCOM_USART_CTRLA_RXPO(0) | SERCOM_USART_CTRLA_TXPO(3)), + /** MUX setting USART_RX_1_TX_0_XCK_1_TE_2 */ + USART_RX_1_TX_0_XCK_1_TE_2 = (SERCOM_USART_CTRLA_RXPO(1) | SERCOM_USART_CTRLA_TXPO(3)), + /** MUX setting USART_RX_2_TX_0_XCK_1_TE_2 */ + USART_RX_2_TX_0_XCK_1_TE_2 = (SERCOM_USART_CTRLA_RXPO(2) | SERCOM_USART_CTRLA_TXPO(3)), + /** MUX setting USART_RX_3_TX_0_XCK_1_TE_2 */ + USART_RX_3_TX_0_XCK_1_TE_2 = (SERCOM_USART_CTRLA_RXPO(3) | SERCOM_USART_CTRLA_TXPO(3)), +#endif +#else + /** MUX setting RX_0_TX_0_XCK_1 */ + USART_RX_0_TX_0_XCK_1 = (SERCOM_USART_CTRLA_RXPO(0)), + /** MUX setting RX_0_TX_2_XCK_3 */ + USART_RX_0_TX_2_XCK_3 = (SERCOM_USART_CTRLA_RXPO(0) | SERCOM_USART_CTRLA_TXPO), + /** MUX setting RX_1_TX_0_XCK_1 */ + USART_RX_1_TX_0_XCK_1 = (SERCOM_USART_CTRLA_RXPO(1)), + /** MUX setting RX_1_TX_2_XCK_3 */ + USART_RX_1_TX_2_XCK_3 = (SERCOM_USART_CTRLA_RXPO(1) | SERCOM_USART_CTRLA_TXPO), + /** MUX setting RX_2_TX_0_XCK_1 */ + USART_RX_2_TX_0_XCK_1 = (SERCOM_USART_CTRLA_RXPO(2)), + /** MUX setting RX_2_TX_2_XCK_3 */ + USART_RX_2_TX_2_XCK_3 = (SERCOM_USART_CTRLA_RXPO(2) | SERCOM_USART_CTRLA_TXPO), + /** MUX setting RX_3_TX_0_XCK_1 */ + USART_RX_3_TX_0_XCK_1 = (SERCOM_USART_CTRLA_RXPO(3)), + /** MUX setting RX_3_TX_2_XCK_3 */ + USART_RX_3_TX_2_XCK_3 = (SERCOM_USART_CTRLA_RXPO(3) | SERCOM_USART_CTRLA_TXPO), +#endif +}; + +/** + * \brief USART Stop Bits enum + * + * Number of stop bits for a frame. + */ +enum usart_stopbits { + /** Each transferred frame contains one stop bit */ + USART_STOPBITS_1 = 0, + /** Each transferred frame contains two stop bits */ + USART_STOPBITS_2 = SERCOM_USART_CTRLB_SBMODE, +}; + +/** + * \brief USART Character Size + * + * Number of bits for the character sent in a frame. + */ +enum usart_character_size { + /** The char being sent in a frame is five bits long */ + USART_CHARACTER_SIZE_5BIT = SERCOM_USART_CTRLB_CHSIZE(5), + /** The char being sent in a frame is six bits long */ + USART_CHARACTER_SIZE_6BIT = SERCOM_USART_CTRLB_CHSIZE(6), + /** The char being sent in a frame is seven bits long */ + USART_CHARACTER_SIZE_7BIT = SERCOM_USART_CTRLB_CHSIZE(7), + /** The char being sent in a frame is eight bits long */ + USART_CHARACTER_SIZE_8BIT = SERCOM_USART_CTRLB_CHSIZE(0), + /** The char being sent in a frame is nine bits long */ + USART_CHARACTER_SIZE_9BIT = SERCOM_USART_CTRLB_CHSIZE(1), +}; + +#ifdef FEATURE_USART_OVER_SAMPLE +/** + * \brief USART Sample Rate + * + * The value of sample rate and baudrate generation mode. + */ +enum usart_sample_rate { + /** 16x over-sampling using arithmetic baudrate generation */ + USART_SAMPLE_RATE_16X_ARITHMETIC = SERCOM_USART_CTRLA_SAMPR(0), + /** 16x over-sampling using fractional baudrate generation */ + USART_SAMPLE_RATE_16X_FRACTIONAL = SERCOM_USART_CTRLA_SAMPR(1), + /** 8x over-sampling using arithmetic baudrate generation */ + USART_SAMPLE_RATE_8X_ARITHMETIC = SERCOM_USART_CTRLA_SAMPR(2), + /** 8x over-sampling using fractional baudrate generation */ + USART_SAMPLE_RATE_8X_FRACTIONAL = SERCOM_USART_CTRLA_SAMPR(3), + /** 3x over-sampling using arithmetic baudrate generation */ + USART_SAMPLE_RATE_3X_ARITHMETIC = SERCOM_USART_CTRLA_SAMPR(4), +}; + +/** + * \brief USART Sample Adjustment + * + * The value of sample number used for majority voting. + */ +enum usart_sample_adjustment { + /** The first, middle and last sample number used for majority voting is 7-8-9 */ + USART_SAMPLE_ADJUSTMENT_7_8_9 = SERCOM_USART_CTRLA_SAMPA(0), + /** The first, middle and last sample number used for majority voting is 9-10-11 */ + USART_SAMPLE_ADJUSTMENT_9_10_11 = SERCOM_USART_CTRLA_SAMPA(1), + /** The first, middle and last sample number used for majority voting is 11-12-13 */ + USART_SAMPLE_ADJUSTMENT_11_12_13 = SERCOM_USART_CTRLA_SAMPA(2), + /** The first, middle and last sample number used for majority voting is 13-14-15 */ + USART_SAMPLE_ADJUSTMENT_13_14_15 = SERCOM_USART_CTRLA_SAMPA(3), +}; +#endif + +#ifdef FEATURE_USART_RS485 +/** + * \brief RS485 Guard Time + * + * The value of RS485 guard time. + */ +enum rs485_guard_time { + /** The guard time is 0-bit time */ + RS485_GUARD_TIME_0_BIT = 0, + /** The guard time is 1-bit time */ + RS485_GUARD_TIME_1_BIT, + /** The guard time is 2-bit times */ + RS485_GUARD_TIME_2_BIT, + /** The guard time is 3-bit times */ + RS485_GUARD_TIME_3_BIT, + /** The guard time is 4-bit times */ + RS485_GUARD_TIME_4_BIT, + /** The guard time is 5-bit times */ + RS485_GUARD_TIME_5_BIT, + /** The guard time is 6-bit times */ + RS485_GUARD_TIME_6_BIT, + /** The guard time is 7-bit times */ + RS485_GUARD_TIME_7_BIT, +}; +#endif + +/** + * \brief USART Transceiver + * + * Select Receiver or Transmitter. + */ +enum usart_transceiver_type { + /** The parameter is for the Receiver */ + USART_TRANSCEIVER_RX, + /** The parameter is for the Transmitter */ + USART_TRANSCEIVER_TX, +}; + +/** + * \brief USART configuration struct + * + * Configuration options for USART. + */ +struct usart_config { + /** USART bit order (MSB or LSB first) */ + enum usart_dataorder data_order; + /** USART in asynchronous or synchronous mode */ + enum usart_transfer_mode transfer_mode; + /** USART parity */ + enum usart_parity parity; + /** Number of stop bits */ + enum usart_stopbits stopbits; + /** USART character size */ + enum usart_character_size character_size; + /** USART pin out */ + enum usart_signal_mux_settings mux_setting; +#ifdef FEATURE_USART_OVER_SAMPLE + /** USART sample rate */ + enum usart_sample_rate sample_rate; + /** USART sample adjustment */ + enum usart_sample_adjustment sample_adjustment; +#endif +#ifdef FEATURE_USART_IMMEDIATE_BUFFER_OVERFLOW_NOTIFICATION + /** Controls when the buffer overflow status bit is asserted when a buffer overflow occurs */ + bool immediate_buffer_overflow_notification; +#endif +#ifdef FEATURE_USART_IRDA + /** Enable IrDA encoding format */ + bool encoding_format_enable; + /** The minimum pulse length required for a pulse to be accepted by the IrDA receiver */ + uint8_t receive_pulse_length; +#endif +#ifdef FEATURE_USART_LIN_SLAVE + /** Enable LIN Slave Support */ + bool lin_slave_enable; +#endif + +#ifdef FEATURE_USART_LIN_MASTER + /** LIN node type */ + enum lin_node_type lin_node; + /** LIN master header delay */ + enum lin_master_header_delay lin_header_delay; + /** LIN Master Break Length */ + enum lin_master_break_length lin_break_length; +#endif + +#ifdef FEATURE_USART_START_FRAME_DECTION + /** Enable start of frame dection */ + bool start_frame_detection_enable; +#endif +#ifdef FEATURE_USART_ISO7816 + /** Enable ISO7816 for smart card interfacing */ + struct iso7816_config_t iso7816_config; +#endif +#ifdef FEATURE_USART_RS485 + /** RS485 guard time */ + enum rs485_guard_time rs485_guard_time; +#endif +#ifdef FEATURE_USART_COLLISION_DECTION + /** Enable collision dection */ + bool collision_detection_enable; +#endif + /** USART baudrate */ + uint32_t baudrate; + /** Enable receiver */ + bool receiver_enable; + /** Enable transmitter */ + bool transmitter_enable; + + /** USART Clock Polarity. + * If true, data changes on falling XCK edge and + * is sampled at rising edge. + * If false, data changes on rising XCK edge and + * is sampled at falling edge. + * */ + bool clock_polarity_inverted; + + /** States whether to use the external clock applied to the XCK pin. + * In synchronous mode the shift register will act directly on the XCK clock. + * In asynchronous mode the XCK will be the input to the USART hardware module. + */ + bool use_external_clock; + /** External clock frequency in synchronous mode. + * This must be set if \c use_external_clock is true. */ + uint32_t ext_clock_freq; + /** If true the USART will be kept running in Standby sleep mode */ + bool run_in_standby; + /** GCLK generator source */ + enum gclk_generator generator_source; + /** PAD0 pinmux. + * + * If current USARTx has several alternative multiplexing I/O pins for PAD0, then + * only one peripheral multiplexing I/O can be enabled for current USARTx PAD0 + * function. Make sure that no other alternative multiplexing I/O is associated + * with the same USARTx PAD0. + */ + uint32_t pinmux_pad0; + /** PAD1 pinmux. + * + * If current USARTx has several alternative multiplexing I/O pins for PAD1, then + * only one peripheral multiplexing I/O can be enabled for current USARTx PAD1 + * function. Make sure that no other alternative multiplexing I/O is associated + * with the same USARTx PAD1. + */ + uint32_t pinmux_pad1; + /** PAD2 pinmux. + * + * If current USARTx has several alternative multiplexing I/O pins for PAD2, then + * only one peripheral multiplexing I/O can be enabled for current USARTx PAD2 + * function. Make sure that no other alternative multiplexing I/O is associated + * with the same USARTx PAD2. + */ + uint32_t pinmux_pad2; + /** PAD3 pinmux. + * + * If current USARTx has several alternative multiplexing I/O pins for PAD3, then + * only one peripheral multiplexing I/O can be enabled for current USARTx PAD3 + * function. Make sure that no other alternative multiplexing I/O is associated + * with the same USARTx PAD3. + */ + uint32_t pinmux_pad3; +}; + +#if USART_CALLBACK_MODE == true +/** + * \brief USART module instance + * + * Forward Declaration for the device instance. + */ +struct usart_module; + +/** + * \brief USART callback type + * + * Type of the callback functions. + */ +typedef void (*usart_callback_t)(struct usart_module *const module); +#endif + +/** + * \brief SERCOM USART driver software device instance structure. + * + * SERCOM USART driver software instance structure, used to retain software + * state information of an associated hardware module instance. + * + * \note The fields of this structure should not be altered by the user + * application; they are reserved for module-internal use only. + */ +struct usart_module { +#if !defined(__DOXYGEN__) + /** Pointer to the hardware instance */ + Sercom *hw; + /** Module lock */ + volatile bool locked; + /** Character size of the data being transferred */ + enum usart_character_size character_size; + /** Receiver enabled */ + bool receiver_enabled; + /** Transmitter enabled */ + bool transmitter_enabled; +#ifdef FEATURE_USART_LIN_SLAVE + /** LIN Slave Support enabled */ + bool lin_slave_enabled; +#endif +#ifdef FEATURE_USART_START_FRAME_DECTION + /** Start of frame dection enabled */ + bool start_frame_detection_enabled; +#endif +#ifdef FEATURE_USART_ISO7816 + /** ISO7816 mode enable */ + bool iso7816_mode_enabled; +#endif +# if USART_CALLBACK_MODE == true + /** Array to store callback function pointers in */ + usart_callback_t callback[USART_CALLBACK_N]; + /** Buffer pointer to where the next received character will be put */ + volatile uint8_t *rx_buffer_ptr; + + /** Buffer pointer to where the next character will be transmitted from + **/ + volatile uint8_t *tx_buffer_ptr; + /** Remaining characters to receive */ + volatile uint16_t remaining_rx_buffer_length; + /** Remaining characters to transmit */ + volatile uint16_t remaining_tx_buffer_length; + /** Bit mask for callbacks registered */ + uint8_t callback_reg_mask; + /** Bit mask for callbacks enabled */ + uint8_t callback_enable_mask; + /** Holds the status of the ongoing or last read operation */ + volatile enum status_code rx_status; + /** Holds the status of the ongoing or last write operation */ + volatile enum status_code tx_status; +# endif +#endif +}; + + /** + * \name Lock/Unlock + * @{ + */ + +/** + * \brief Attempt to get lock on driver instance + * + * This function checks the instance's lock, which indicates whether or not it + * is currently in use, and sets the lock if it was not already set. + * + * The purpose of this is to enable exclusive access to driver instances, so + * that, e.g., transactions by different services will not interfere with each + * other. + * + * \param[in,out] module Pointer to the driver instance to lock + * + * \retval STATUS_OK If the module was locked + * \retval STATUS_BUSY If the module was already locked + */ +static inline enum status_code usart_lock( + struct usart_module *const module) +{ + enum status_code status; + + system_interrupt_enter_critical_section(); + + if (module->locked) { + status = STATUS_BUSY; + } else { + module->locked = true; + status = STATUS_OK; + } + + system_interrupt_leave_critical_section(); + + return status; +} + +/** + * \brief Unlock driver instance + * + * This function clears the instance lock, indicating that it is available for + * use. + * + * \param[in,out] module Pointer to the driver instance to lock + * + */ +static inline void usart_unlock(struct usart_module *const module) +{ + module->locked = false; +} + +/** @} */ + +/** + * \brief Check if peripheral is busy syncing registers across clock domains + * + * Return peripheral synchronization status. If doing a non-blocking + * implementation this function can be used to check the sync state and hold of + * any new actions until sync is complete. If this function is not run; the + * functions will block until the sync has completed. + * + * \param[in] module Pointer to peripheral module + * + * \return Peripheral sync status. + * + * \retval true Peripheral is busy syncing + * \retval false Peripheral is not busy syncing and can be read/written without + * stalling the bus + */ +static inline bool usart_is_syncing( + const struct usart_module *const module) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + SercomUsart *const usart_hw = &(module->hw->USART); + +#ifdef FEATURE_USART_SYNC_SCHEME_V2 + return (usart_hw->SYNCBUSY.reg); +#else + return (usart_hw->STATUS.reg & SERCOM_USART_STATUS_SYNCBUSY); +#endif +} + +#if !defined (__DOXYGEN__) +/** + * \internal + * Waits until synchronization is complete + */ +static inline void _usart_wait_for_sync( + const struct usart_module *const module) +{ + /* Sanity check */ + Assert(module); + + while (usart_is_syncing(module)) { + /* Wait until the synchronization is complete */ + } +} +#endif + +/** + * \brief Initializes the device to predefined defaults + * + * Initialize the USART device to predefined defaults: + * - 8-bit asynchronous USART + * - No parity + * - One stop bit + * - 9600 baud + * - Transmitter enabled + * - Receiver enabled + * - GCLK generator 0 as clock source + * - Default pin configuration + * + * The configuration struct will be updated with the default + * configuration. + * + * \param[in,out] config Pointer to configuration struct + */ +static inline void usart_get_config_defaults( + struct usart_config *const config) +{ + /* Sanity check arguments */ + Assert(config); + + /* Set default config in the config struct */ + config->data_order = USART_DATAORDER_LSB; + config->transfer_mode = USART_TRANSFER_ASYNCHRONOUSLY; + config->parity = USART_PARITY_NONE; + config->stopbits = USART_STOPBITS_1; + config->character_size = USART_CHARACTER_SIZE_8BIT; + config->baudrate = 9600; + config->receiver_enable = true; + config->transmitter_enable = true; + config->clock_polarity_inverted = false; + config->use_external_clock = false; + config->ext_clock_freq = 0; + config->mux_setting = USART_RX_1_TX_2_XCK_3; + config->run_in_standby = false; + config->generator_source = GCLK_GENERATOR_0; + config->pinmux_pad0 = PINMUX_DEFAULT; + config->pinmux_pad1 = PINMUX_DEFAULT; + config->pinmux_pad2 = PINMUX_DEFAULT; + config->pinmux_pad3 = PINMUX_DEFAULT; +#ifdef FEATURE_USART_OVER_SAMPLE + config->sample_adjustment = USART_SAMPLE_ADJUSTMENT_7_8_9; + config->sample_rate = USART_SAMPLE_RATE_16X_ARITHMETIC; +#endif +#ifdef FEATURE_USART_LIN_SLAVE + config->lin_slave_enable = false; +#endif + +#ifdef FEATURE_USART_LIN_MASTER + config->lin_node = LIN_INVALID_MODE; + config->lin_header_delay = LIN_MASTER_HEADER_DELAY_0; + config->lin_break_length = LIN_MASTER_BREAK_LENGTH_13_BIT; +#endif + +#ifdef FEATURE_USART_IMMEDIATE_BUFFER_OVERFLOW_NOTIFICATION + config->immediate_buffer_overflow_notification = false; +#endif +#ifdef FEATURE_USART_START_FRAME_DECTION + config->start_frame_detection_enable = false; +#endif +#ifdef FEATURE_USART_IRDA + config->encoding_format_enable = false; + config->receive_pulse_length = 19; +#endif +#ifdef FEATURE_USART_ISO7816 + config->iso7816_config.enabled = false; + config->iso7816_config.guard_time = ISO7816_GUARD_TIME_2_BIT; + config->iso7816_config.protocol_t = ISO7816_PROTOCOL_T_0; + config->iso7816_config.enable_inverse = false; + config->iso7816_config.inhibit_nack = ISO7816_INHIBIT_NACK_DISABLE; + config->iso7816_config.successive_recv_nack = ISO7816_SUCCESSIVE_RECV_NACK_DISABLE; + config->iso7816_config.max_iterations = 7; +#endif +#ifdef FEATURE_USART_COLLISION_DECTION + config->collision_detection_enable = false; +#endif +#ifdef FEATURE_USART_RS485 + config->rs485_guard_time = RS485_GUARD_TIME_0_BIT; +#endif +} + +enum status_code usart_init( + struct usart_module *const module, + Sercom *const hw, + const struct usart_config *const config); + +/** + * \brief Enable the module + * + * Enables the USART module. + * + * \param[in] module Pointer to USART software instance struct + */ +static inline void usart_enable( + const struct usart_module *const module) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + /* Get a pointer to the hardware module instance */ + SercomUsart *const usart_hw = &(module->hw->USART); + +#if USART_CALLBACK_MODE == true + /* Enable Global interrupt for module */ + system_interrupt_enable(_sercom_get_interrupt_vector(module->hw)); +#endif + + /* Wait until synchronization is complete */ + _usart_wait_for_sync(module); + + /* Enable USART module */ + usart_hw->CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE; +} + +/** + * \brief Disable module + * + * Disables the USART module. + * + * \param[in] module Pointer to USART software instance struct + */ +static inline void usart_disable( + const struct usart_module *const module) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + /* Get a pointer to the hardware module instance */ + SercomUsart *const usart_hw = &(module->hw->USART); + +#if USART_CALLBACK_MODE == true + /* Disable Global interrupt for module */ + system_interrupt_disable(_sercom_get_interrupt_vector(module->hw)); +#endif + + /* Wait until synchronization is complete */ + _usart_wait_for_sync(module); + + /* Disable USART module */ + usart_hw->CTRLA.reg &= ~SERCOM_USART_CTRLA_ENABLE; +} + +/** + * \brief Resets the USART module + * + * Disables and resets the USART module. + * + * \param[in] module Pointer to the USART software instance struct + */ +static inline void usart_reset( + const struct usart_module *const module) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + /* Get a pointer to the hardware module instance */ + SercomUsart *const usart_hw = &(module->hw->USART); + + usart_disable(module); + + /* Wait until synchronization is complete */ + _usart_wait_for_sync(module); + + /* Reset module */ + usart_hw->CTRLA.reg = SERCOM_USART_CTRLA_SWRST; +} + +/** + * \name Writing and Reading + * @{ + */ +enum status_code usart_write_wait( + struct usart_module *const module, + const uint16_t tx_data); + +enum status_code usart_read_wait( + struct usart_module *const module, + uint16_t *const rx_data); + +enum status_code usart_write_buffer_wait( + struct usart_module *const module, + const uint8_t *tx_data, + uint16_t length); + +enum status_code usart_read_buffer_wait( + struct usart_module *const module, + uint8_t *rx_data, + uint16_t length); +/** @} */ + +/** + * \name Enabling/Disabling Receiver and Transmitter + * @{ + */ + +/** + * \brief Enable Transceiver + * + * Enable the given transceiver. Either RX or TX. + * + * \param[in] module Pointer to USART software instance struct + * \param[in] transceiver_type Transceiver type + */ +static inline void usart_enable_transceiver( + struct usart_module *const module, + enum usart_transceiver_type transceiver_type) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + /* Get a pointer to the hardware module instance */ + SercomUsart *const usart_hw = &(module->hw->USART); + + /* Wait until synchronization is complete */ + _usart_wait_for_sync(module); + + switch (transceiver_type) { + case USART_TRANSCEIVER_RX: + /* Enable RX */ + usart_hw->CTRLB.reg |= SERCOM_USART_CTRLB_RXEN; + module->receiver_enabled = true; + break; + + case USART_TRANSCEIVER_TX: + /* Enable TX */ + usart_hw->CTRLB.reg |= SERCOM_USART_CTRLB_TXEN; + module->transmitter_enabled = true; + break; + } + _usart_wait_for_sync(module); +} + +/** + * \brief Disable Transceiver + * + * Disable the given transceiver (RX or TX). + * + * \param[in] module Pointer to USART software instance struct + * \param[in] transceiver_type Transceiver type + */ +static inline void usart_disable_transceiver( + struct usart_module *const module, + enum usart_transceiver_type transceiver_type) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + /* Get a pointer to the hardware module instance */ + SercomUsart *const usart_hw = &(module->hw->USART); + + /* Wait until synchronization is complete */ + _usart_wait_for_sync(module); + + switch (transceiver_type) { + case USART_TRANSCEIVER_RX: + /* Disable RX */ + usart_hw->CTRLB.reg &= ~SERCOM_USART_CTRLB_RXEN; + module->receiver_enabled = false; + break; + + case USART_TRANSCEIVER_TX: + /* Disable TX */ + usart_hw->CTRLB.reg &= ~SERCOM_USART_CTRLB_TXEN; + module->transmitter_enabled = false; + break; + } +} + +/** @} */ + +#ifdef FEATURE_USART_LIN_MASTER +/** + * \name LIN Master Command and Status + * @{ + */ + +/** + * \brief Sending LIN command. + * + * Sending LIN command. + * + * \param[in] module Pointer to USART software instance struct + * \param[in] cmd Cammand type + */ +static inline void lin_master_send_cmd( + struct usart_module *const module, + enum lin_master_cmd cmd) +{ + SercomUsart *const usart_hw = &(module->hw->USART); + _usart_wait_for_sync(module); + usart_hw->CTRLB.reg |= cmd; +} + +/** + * \brief Get LIN transmission status + * + * Get LIN transmission status. + * + * \param[in] module Pointer to USART software instance struct + * + * \return Status of LIN master transmission. + * \retval true Data transmission completed + * \retval false Transmission is ongoing + */ +static inline bool lin_master_transmission_status(struct usart_module *const module) +{ + SercomUsart *const usart_hw = &(module->hw->USART); + return ((usart_hw->STATUS.reg & SERCOM_USART_STATUS_TXE)? true:false); +} + +/** @} */ +#endif + +#ifdef __cplusplus +} +#endif + +/** @} */ + +/** +* \page asfdoc_sam0_sercom_usart_extra Extra Information for SERCOM USART Driver +* +* \section asfdoc_sam0_sercom_usart_extra_acronyms Acronyms +* +* Below is a table listing the acronyms used in this module, along with their +* intended meanings. +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +*
AcronymDescription
SERCOMSerial Communication Interface
USARTUniversal Synchronous and Asynchronous Serial Receiver and Transmitter
LSBLeast Significant Bit
MSBMost Significant Bit
DMADirect Memory Access
+* +* +* \section asfdoc_sam0_sercom_usart_extra_dependencies Dependencies +* This driver has the following dependencies: +* +* - \ref asfdoc_sam0_system_pinmux_group "System Pin Multiplexer Driver" +* - \ref asfdoc_sam0_system_clock_group "System clock configuration" +* +* +* \section asfdoc_sam0_sercom_usart_extra_errata Errata +* There are no errata related to this driver. +* +* +* \section asfdoc_sam0_sercom_usart_extra_history Module History +* An overview of the module history is presented in the table below, with +* details on the enhancements and fixes made to the module since its first +* release. The current version of this corresponds to the newest version in +* the table. +* + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Changelog
Added new feature as below: + * \li ISO7816 + *
Added new features as below: + * \li LIN master + * \li RS485 + *
Added new features as below: + * \li Oversample + * \li Buffer overflow notification + * \li Irda + * \li Lin slave + * \li Start frame detection + * \li Hardware flow control + * \li Collision detection + * \li DMA support
\li Added new \c transmitter_enable and \c receiver_enable Boolean + * values to \c struct usart_config + * \li Altered \c usart_write_* and usart_read_* functions to abort with + * an error code if the relevant transceiver is not enabled + * \li Fixed \c usart_write_buffer_wait() and \c usart_read_buffer_wait() + * not aborting correctly when a timeout condition occurs
Initial Release
+*/ + +/** + * \page asfdoc_sam0_sercom_usart_exqsg Examples for SERCOM USART Driver + * + * This is a list of the available Quick Start guides (QSGs) and example + * applications for \ref asfdoc_sam0_sercom_usart_group. QSGs are simple examples with + * step-by-step instructions to configure and use this driver in a selection of + * use cases. Note that a QSG can be compiled as a standalone application or be + * added to the user application. + * + * - \subpage asfdoc_sam0_sercom_usart_basic_use_case + * \if USART_CALLBACK_MODE + * - \subpage asfdoc_sam0_sercom_usart_callback_use_case + * \endif + * - \subpage asfdoc_sam0_sercom_usart_dma_use_case + * - \subpage asfdoc_sam0_sercom_usart_lin_use_case + */ + +/** + * \page asfdoc_sam0_sercom_usart_mux_settings SERCOM USART MUX Settings + * + * The following lists the possible internal SERCOM module pad function + * assignments, for the four SERCOM pads when in USART mode. Note that this is + * in addition to the physical GPIO pin MUX of the device, and can be used in + * conjunction to optimize the serial data pin-out. + * + * When TX and RX are connected to the same pin, the USART will operate in + * half-duplex mode if both one transmitter and several receivers are enabled. + * + * \note When RX and XCK are connected to the same pin, the receiver must not + * be enabled if the USART is configured to use an external clock. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
MUX/PadPAD 0PAD 1PAD 2PAD 3
RX_0_TX_0_XCK_1TX / RXXCK--
RX_0_TX_2_XCK_3RX-TXXCK
RX_1_TX_0_XCK_1TXRX / XCK--
RX_1_TX_2_XCK_3-RXTXXCK
RX_2_TX_0_XCK_1TXXCKRX-
RX_2_TX_2_XCK_3--TX / RXXCK
RX_3_TX_0_XCK_1TXXCK-RX
RX_3_TX_2_XCK_3--TXRX / XCK
+ * + * \page asfdoc_sam0_sercom_usart_document_revision_history Document Revision History + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Doc. Rev. + * Date + * Comments + *
42118F12/2015Added support for SAM L21/L22, SAM DA1, SAM D09, SAMR30/R34 and SAM C20/C21
42118E12/2014Added support for SAM R21 and SAM D10/D11
42118D01/2014Added support for SAM D21
42118C10/2013Replaced the pad multiplexing documentation with a condensed table
42118B06/2013Corrected documentation typos
42118A06/2013Initial release
+ */ +#endif /* USART_H_INCLUDED */ diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/usart/usart_interrupt.c b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/usart/usart_interrupt.c new file mode 100644 index 000000000..39df7d734 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/usart/usart_interrupt.c @@ -0,0 +1,656 @@ +/** + * \file + * + * \brief SAM SERCOM USART Asynchronous Driver + * + * Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#include "usart_interrupt.h" + +/** + * \internal + * Asynchronous write of a buffer with a given length + * + * \param[in] module Pointer to USART software instance struct + * \param[in] tx_data Pointer to data to be transmitted + * \param[in] length Length of data buffer + * + */ +enum status_code _usart_write_buffer( + struct usart_module *const module, + uint8_t *tx_data, + uint16_t length) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + Assert(tx_data); + + /* Get a pointer to the hardware module instance */ + SercomUsart *const usart_hw = &(module->hw->USART); + + system_interrupt_enter_critical_section(); + + /* Check if the USART transmitter is busy */ + if (module->remaining_tx_buffer_length > 0) { + system_interrupt_leave_critical_section(); + return STATUS_BUSY; + } + + /* Write parameters to the device instance */ + module->remaining_tx_buffer_length = length; + + system_interrupt_leave_critical_section(); + + module->tx_buffer_ptr = tx_data; + module->tx_status = STATUS_BUSY; + + /* Enable the Data Register Empty Interrupt */ + usart_hw->INTENSET.reg = SERCOM_USART_INTFLAG_DRE; + + return STATUS_OK; +} + +/** + * \internal + * Asynchronous read of a buffer with a given length + * + * \param[in] module Pointer to USART software instance struct + * \param[in] rx_data Pointer to data to be received + * \param[in] length Length of data buffer + * + */ +enum status_code _usart_read_buffer( + struct usart_module *const module, + uint8_t *rx_data, + uint16_t length) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + Assert(rx_data); + + /* Get a pointer to the hardware module instance */ + SercomUsart *const usart_hw = &(module->hw->USART); + + system_interrupt_enter_critical_section(); + + /* Check if the USART receiver is busy */ + if (module->remaining_rx_buffer_length > 0) { + system_interrupt_leave_critical_section(); + return STATUS_BUSY; + } + + /* Set length for the buffer and the pointer, and let + * the interrupt handler do the rest */ + module->remaining_rx_buffer_length = length; + + system_interrupt_leave_critical_section(); + + module->rx_buffer_ptr = rx_data; + module->rx_status = STATUS_BUSY; + + /* Enable the RX Complete Interrupt */ + usart_hw->INTENSET.reg = SERCOM_USART_INTFLAG_RXC; + +#ifdef FEATURE_USART_LIN_SLAVE + /* Enable the break character is received Interrupt */ + if(module->lin_slave_enabled) { + usart_hw->INTENSET.reg = SERCOM_USART_INTFLAG_RXBRK; + } +#endif + +#ifdef FEATURE_USART_START_FRAME_DECTION + /* Enable a start condition is detected Interrupt */ + if(module->start_frame_detection_enabled) { + usart_hw->INTENSET.reg = SERCOM_USART_INTFLAG_RXS; + } +#endif + + return STATUS_OK; +} + +/** + * \brief Registers a callback + * + * Registers a callback function, which is implemented by the user. + * + * \note The callback must be enabled by \ref usart_enable_callback + * in order for the interrupt handler to call it when the conditions for + * the callback type are met. + * + * \param[in] module Pointer to USART software instance struct + * \param[in] callback_func Pointer to callback function + * \param[in] callback_type Callback type given by an enum + * + */ +void usart_register_callback( + struct usart_module *const module, + usart_callback_t callback_func, + enum usart_callback callback_type) +{ + /* Sanity check arguments */ + Assert(module); + Assert(callback_func); + + /* Register callback function */ + module->callback[callback_type] = callback_func; + + /* Set the bit corresponding to the callback_type */ + module->callback_reg_mask |= (1 << callback_type); +} + +/** + * \brief Unregisters a callback + * + * Unregisters a callback function, which is implemented by the user. + * + * \param[in,out] module Pointer to USART software instance struct + * \param[in] callback_type Callback type given by an enum + * + */ +void usart_unregister_callback( + struct usart_module *const module, + enum usart_callback callback_type) +{ + /* Sanity check arguments */ + Assert(module); + + /* Unregister callback function */ + module->callback[callback_type] = NULL; + + /* Clear the bit corresponding to the callback_type */ + module->callback_reg_mask &= ~(1 << callback_type); +} + +/** + * \brief Asynchronous write a single char + * + * Sets up the driver to write the data given. If registered and enabled, + * a callback function will be called when the transmit is completed. + * + * \param[in] module Pointer to USART software instance struct + * \param[in] tx_data Data to transfer + * + * \returns Status of the operation. + * \retval STATUS_OK If operation was completed + * \retval STATUS_BUSY If operation was not completed, due to the + * USART module being busy + * \retval STATUS_ERR_DENIED If the transmitter is not enabled + */ +enum status_code usart_write_job( + struct usart_module *const module, + const uint16_t *tx_data) +{ + /* Sanity check arguments */ + Assert(module); + Assert(tx_data); + + + /* Check that the transmitter is enabled */ + if (!(module->transmitter_enabled)) { + return STATUS_ERR_DENIED; + } + + /* Call internal write buffer function with length 1 */ + return _usart_write_buffer(module, (uint8_t *)tx_data, 1); +} + +/** + * \brief Asynchronous read a single char + * + * Sets up the driver to read data from the USART module to the data + * pointer given. If registered and enabled, a callback will be called + * when the receiving is completed. + * + * \param[in] module Pointer to USART software instance struct + * \param[out] rx_data Pointer to where received data should be put + * + * \returns Status of the operation. + * \retval STATUS_OK If operation was completed + * \retval STATUS_BUSY If operation was not completed + */ +enum status_code usart_read_job( + struct usart_module *const module, + uint16_t *const rx_data) +{ + /* Sanity check arguments */ + Assert(module); + Assert(rx_data); + + /* Call internal read buffer function with length 1 */ + return _usart_read_buffer(module, (uint8_t *)rx_data, 1); +} + +/** + * \brief Asynchronous buffer write + * + * Sets up the driver to write a given buffer over the USART. If registered and + * enabled, a callback function will be called. + * + * \param[in] module Pointer to USART software instance struct + * \param[in] tx_data Pointer do data buffer to transmit + * \param[in] length Length of the data to transmit + * + * \note If using 9-bit data, the array that *tx_data point to should be defined + * as uint16_t array and should be casted to uint8_t* pointer. Because it + * is an address pointer, the highest byte is not discarded. For example: + * \code + #define TX_LEN 3 + uint16_t tx_buf[TX_LEN] = {0x0111, 0x0022, 0x0133}; + usart_write_buffer_job(&module, (uint8_t*)tx_buf, TX_LEN); + \endcode + * + * \returns Status of the operation. + * \retval STATUS_OK If operation was completed successfully. + * \retval STATUS_BUSY If operation was not completed, due to the + * USART module being busy + * \retval STATUS_ERR_INVALID_ARG If operation was not completed, due to invalid + * arguments + * \retval STATUS_ERR_DENIED If the transmitter is not enabled + */ +enum status_code usart_write_buffer_job( + struct usart_module *const module, + uint8_t *tx_data, + uint16_t length) +{ + /* Sanity check arguments */ + Assert(module); + Assert(tx_data); + + if (length == 0) { + return STATUS_ERR_INVALID_ARG; + } + + /* Check that the transmitter is enabled */ + if (!(module->transmitter_enabled)) { + return STATUS_ERR_DENIED; + } + + /* Issue internal asynchronous write */ + return _usart_write_buffer(module, tx_data, length); +} + +/** + * \brief Asynchronous buffer read + * + * Sets up the driver to read from the USART to a given buffer. If registered + * and enabled, a callback function will be called. + * + * \param[in] module Pointer to USART software instance struct + * \param[out] rx_data Pointer to data buffer to receive + * \param[in] length Data buffer length + * + * \note If using 9-bit data, the array that *rx_data point to should be defined + * as uint16_t array and should be casted to uint8_t* pointer. Because it + * is an address pointer, the highest byte is not discarded. For example: + * \code + #define RX_LEN 3 + uint16_t rx_buf[RX_LEN] = {0x0,}; + usart_read_buffer_job(&module, (uint8_t*)rx_buf, RX_LEN); + \endcode + * + * \returns Status of the operation. + * \retval STATUS_OK If operation was completed + * \retval STATUS_BUSY If operation was not completed, due to the + * USART module being busy + * \retval STATUS_ERR_INVALID_ARG If operation was not completed, due to invalid + * arguments + * \retval STATUS_ERR_DENIED If the transmitter is not enabled + */ +enum status_code usart_read_buffer_job( + struct usart_module *const module, + uint8_t *rx_data, + uint16_t length) +{ + /* Sanity check arguments */ + Assert(module); + Assert(rx_data); + + if (length == 0) { + return STATUS_ERR_INVALID_ARG; + } + + /* Check that the receiver is enabled */ + if (!(module->receiver_enabled)) { + return STATUS_ERR_DENIED; + } + + /* Issue internal asynchronous read */ + return _usart_read_buffer(module, rx_data, length); +} + +/** + * \brief Cancels ongoing read/write operation + * + * Cancels the ongoing read/write operation modifying parameters in the + * USART software struct. + * + * \param[in] module Pointer to USART software instance struct + * \param[in] transceiver_type Transfer type to cancel + */ +void usart_abort_job( + struct usart_module *const module, + enum usart_transceiver_type transceiver_type) +{ + /* Sanity check arguments */ + Assert(module); + Assert(module->hw); + + /* Get a pointer to the hardware module instance */ + SercomUsart *const usart_hw = &(module->hw->USART); + + switch(transceiver_type) { + case USART_TRANSCEIVER_RX: + /* Clear the interrupt flag in order to prevent the receive + * complete callback to fire */ + usart_hw->INTFLAG.reg = SERCOM_USART_INTFLAG_RXC; + + /* Clear the software reception buffer */ + module->remaining_rx_buffer_length = 0; + + break; + + case USART_TRANSCEIVER_TX: + /* Clear the interrupt flag in order to prevent the receive + * complete callback to fire */ + usart_hw->INTFLAG.reg = SERCOM_USART_INTFLAG_TXC; + + /* Clear the software reception buffer */ + module->remaining_tx_buffer_length = 0; + + break; + } +} + +/** + * \brief Get status from the ongoing or last asynchronous transfer operation + * + * Returns the error from a given ongoing or last asynchronous transfer operation. + * Either from a read or write transfer. + * + * \param[in] module Pointer to USART software instance struct + * \param[in] transceiver_type Transfer type to check + * + * \return Status of the given job. + * \retval STATUS_OK No error occurred during the last transfer + * \retval STATUS_BUSY A transfer is ongoing + * \retval STATUS_ERR_BAD_DATA The last operation was aborted due to a + * parity error. The transfer could be affected + * by external noise + * \retval STATUS_ERR_BAD_FORMAT The last operation was aborted due to a + * frame error + * \retval STATUS_ERR_OVERFLOW The last operation was aborted due to a + * buffer overflow + * \retval STATUS_ERR_INVALID_ARG An invalid transceiver enum given + */ +enum status_code usart_get_job_status( + struct usart_module *const module, + enum usart_transceiver_type transceiver_type) +{ + /* Sanity check arguments */ + Assert(module); + + /* Variable for status code */ + enum status_code status_code; + + switch(transceiver_type) { + case USART_TRANSCEIVER_RX: + status_code = module->rx_status; + break; + + case USART_TRANSCEIVER_TX: + status_code = module->tx_status; + break; + + default: + status_code = STATUS_ERR_INVALID_ARG; + break; + } + + return status_code; +} + +/** + * \internal + * Handles interrupts as they occur, and it will run callback functions + * which are registered and enabled. + * + * \param[in] instance ID of the SERCOM instance calling the interrupt + * handler. + */ +void _usart_interrupt_handler( + uint8_t instance) +{ + /* Temporary variables */ + uint16_t interrupt_status; + uint16_t callback_status; + uint8_t error_code; + + + /* Get device instance from the look-up table */ + struct usart_module *module + = (struct usart_module *)_sercom_instances[instance]; + + /* Pointer to the hardware module instance */ + SercomUsart *const usart_hw + = &(module->hw->USART); + + /* Wait for the synchronization to complete */ + _usart_wait_for_sync(module); + + /* Read and mask interrupt flag register */ + interrupt_status = usart_hw->INTFLAG.reg; + interrupt_status &= usart_hw->INTENSET.reg; + callback_status = module->callback_reg_mask & + module->callback_enable_mask; + + /* Check if a DATA READY interrupt has occurred, + * and if there is more to transfer */ + if (interrupt_status & SERCOM_USART_INTFLAG_DRE) { + if (module->remaining_tx_buffer_length) { + /* Write value will be at least 8-bits long */ + uint16_t data_to_send = *(module->tx_buffer_ptr); + /* Increment 8-bit pointer */ + (module->tx_buffer_ptr)++; + + if (module->character_size == USART_CHARACTER_SIZE_9BIT) { + data_to_send |= (*(module->tx_buffer_ptr) << 8); + /* Increment 8-bit pointer */ + (module->tx_buffer_ptr)++; + } + /* Write the data to send */ + usart_hw->DATA.reg = (data_to_send & SERCOM_USART_DATA_MASK); + + if (--(module->remaining_tx_buffer_length) == 0) { + /* Disable the Data Register Empty Interrupt */ + usart_hw->INTENCLR.reg = SERCOM_USART_INTFLAG_DRE; + /* Enable Transmission Complete interrupt */ + usart_hw->INTENSET.reg = SERCOM_USART_INTFLAG_TXC; + + } + } else { + usart_hw->INTENCLR.reg = SERCOM_USART_INTFLAG_DRE; + } + } + + /* Check if the Transmission Complete interrupt has occurred and + * that the transmit buffer is empty */ + if (interrupt_status & SERCOM_USART_INTFLAG_TXC) { + + /* Disable TX Complete Interrupt, and set STATUS_OK */ + usart_hw->INTENCLR.reg = SERCOM_USART_INTFLAG_TXC; + module->tx_status = STATUS_OK; + + /* Run callback if registered and enabled */ + if (callback_status & (1 << USART_CALLBACK_BUFFER_TRANSMITTED)) { + (*(module->callback[USART_CALLBACK_BUFFER_TRANSMITTED]))(module); + } + } + + /* Check if the Receive Complete interrupt has occurred, and that + * there's more data to receive */ + if (interrupt_status & SERCOM_USART_INTFLAG_RXC) { + + if (module->remaining_rx_buffer_length) { + /* Read out the status code and mask away all but the 4 LSBs*/ + error_code = (uint8_t)(usart_hw->STATUS.reg & SERCOM_USART_STATUS_MASK); +#if !SAMD20 + /* CTS status should not be considered as an error */ + if(error_code & SERCOM_USART_STATUS_CTS) { + error_code &= ~SERCOM_USART_STATUS_CTS; + } +#endif +#ifdef FEATURE_USART_LIN_MASTER + /* TXE status should not be considered as an error */ + if(error_code & SERCOM_USART_STATUS_TXE) { + error_code &= ~SERCOM_USART_STATUS_TXE; + } +#endif + /* Check if an error has occurred during the receiving */ + if (error_code) { + /* Check which error occurred */ + if (error_code & SERCOM_USART_STATUS_FERR) { + /* Store the error code and clear flag by writing 1 to it */ + module->rx_status = STATUS_ERR_BAD_FORMAT; + usart_hw->STATUS.reg = SERCOM_USART_STATUS_FERR; + } else if (error_code & SERCOM_USART_STATUS_BUFOVF) { + /* Store the error code and clear flag by writing 1 to it */ + module->rx_status = STATUS_ERR_OVERFLOW; + usart_hw->STATUS.reg = SERCOM_USART_STATUS_BUFOVF; + } else if (error_code & SERCOM_USART_STATUS_PERR) { + /* Store the error code and clear flag by writing 1 to it */ + module->rx_status = STATUS_ERR_BAD_DATA; + usart_hw->STATUS.reg = SERCOM_USART_STATUS_PERR; + } +#ifdef FEATURE_USART_LIN_SLAVE + else if (error_code & SERCOM_USART_STATUS_ISF) { + /* Store the error code and clear flag by writing 1 to it */ + module->rx_status = STATUS_ERR_PROTOCOL; + usart_hw->STATUS.reg = SERCOM_USART_STATUS_ISF; + } +#endif +#ifdef FEATURE_USART_COLLISION_DECTION + else if (error_code & SERCOM_USART_STATUS_COLL) { + /* Store the error code and clear flag by writing 1 to it */ + module->rx_status = STATUS_ERR_PACKET_COLLISION; + usart_hw->STATUS.reg = SERCOM_USART_STATUS_COLL; + } +#endif + + /* Run callback if registered and enabled */ + if (callback_status + & (1 << USART_CALLBACK_ERROR)) { + (*(module->callback[USART_CALLBACK_ERROR]))(module); + } + + } else { + + /* Read current packet from DATA register, + * increment buffer pointer and decrement buffer length */ + uint16_t received_data = (usart_hw->DATA.reg & SERCOM_USART_DATA_MASK); + + /* Read value will be at least 8-bits long */ + *(module->rx_buffer_ptr) = received_data; + /* Increment 8-bit pointer */ + module->rx_buffer_ptr += 1; + + if (module->character_size == USART_CHARACTER_SIZE_9BIT) { + /* 9-bit data, write next received byte to the buffer */ + *(module->rx_buffer_ptr) = (received_data >> 8); + /* Increment 8-bit pointer */ + module->rx_buffer_ptr += 1; + } + + /* Check if the last character have been received */ + if(--(module->remaining_rx_buffer_length) == 0) { + /* Disable RX Complete Interrupt, + * and set STATUS_OK */ + usart_hw->INTENCLR.reg = SERCOM_USART_INTFLAG_RXC; + module->rx_status = STATUS_OK; + + /* Run callback if registered and enabled */ + if (callback_status + & (1 << USART_CALLBACK_BUFFER_RECEIVED)) { + (*(module->callback[USART_CALLBACK_BUFFER_RECEIVED]))(module); + } + } + } + } else { + /* This should not happen. Disable Receive Complete interrupt. */ + usart_hw->INTENCLR.reg = SERCOM_USART_INTFLAG_RXC; + } + } + +#ifdef FEATURE_USART_HARDWARE_FLOW_CONTROL + if (interrupt_status & SERCOM_USART_INTFLAG_CTSIC) { + /* Disable interrupts */ + usart_hw->INTENCLR.reg = SERCOM_USART_INTENCLR_CTSIC; + /* Clear interrupt flag */ + usart_hw->INTFLAG.reg = SERCOM_USART_INTFLAG_CTSIC; + + /* Run callback if registered and enabled */ + if (callback_status & (1 << USART_CALLBACK_CTS_INPUT_CHANGE)) { + (*(module->callback[USART_CALLBACK_CTS_INPUT_CHANGE]))(module); + } + } +#endif + +#ifdef FEATURE_USART_LIN_SLAVE + if (interrupt_status & SERCOM_USART_INTFLAG_RXBRK) { + /* Disable interrupts */ + usart_hw->INTENCLR.reg = SERCOM_USART_INTENCLR_RXBRK; + /* Clear interrupt flag */ + usart_hw->INTFLAG.reg = SERCOM_USART_INTFLAG_RXBRK; + + /* Run callback if registered and enabled */ + if (callback_status & (1 << USART_CALLBACK_BREAK_RECEIVED)) { + (*(module->callback[USART_CALLBACK_BREAK_RECEIVED]))(module); + } + } +#endif + +#ifdef FEATURE_USART_START_FRAME_DECTION + if (interrupt_status & SERCOM_USART_INTFLAG_RXS) { + /* Disable interrupts */ + usart_hw->INTENCLR.reg = SERCOM_USART_INTENCLR_RXS; + /* Clear interrupt flag */ + usart_hw->INTFLAG.reg = SERCOM_USART_INTFLAG_RXS; + + /* Run callback if registered and enabled */ + if (callback_status & (1 << USART_CALLBACK_START_RECEIVED)) { + (*(module->callback[USART_CALLBACK_START_RECEIVED]))(module); + } + } +#endif +} + diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/usart/usart_interrupt.h b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/usart/usart_interrupt.h new file mode 100644 index 000000000..50263720d --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/sercom/usart/usart_interrupt.h @@ -0,0 +1,167 @@ +/** + * \file + * + * \brief SAM SERCOM USART Asynchronous Driver + * + * Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#ifndef USART_INTERRUPT_H_INCLUDED +#define USART_INTERRUPT_H_INCLUDED + +#include "usart.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(__DOXYGEN__) +enum status_code _usart_write_buffer( + struct usart_module *const module, + uint8_t *tx_data, + uint16_t length); + +enum status_code _usart_read_buffer( + struct usart_module *const module, + uint8_t *rx_data, + uint16_t length); + +void _usart_interrupt_handler( + uint8_t instance); +#endif + +/** + * \addtogroup asfdoc_sam0_sercom_usart_group + * + * @{ + */ + +/** + * \name Callback Management + * @{ + */ +void usart_register_callback( + struct usart_module *const module, + usart_callback_t callback_func, + enum usart_callback callback_type); + +void usart_unregister_callback( + struct usart_module *module, + enum usart_callback callback_type); + +/** + * \brief Enables callback + * + * Enables the callback function registered by the \ref usart_register_callback. + * The callback function will be called from the interrupt handler when the + * conditions for the callback type are met. + * + * \param[in] module Pointer to USART software instance struct + * \param[in] callback_type Callback type given by an enum + */ +static inline void usart_enable_callback( + struct usart_module *const module, + enum usart_callback callback_type) +{ + /* Sanity check arguments */ + Assert(module); + + /* Enable callback */ + module->callback_enable_mask |= (1 << callback_type); + +} + +/** + * \brief Disable callback + * + * Disables the callback function registered by the \ref usart_register_callback, + * and the callback will not be called from the interrupt routine. + * + * \param[in] module Pointer to USART software instance struct + * \param[in] callback_type Callback type given by an enum + */ +static inline void usart_disable_callback( + struct usart_module *const module, + enum usart_callback callback_type) +{ + /* Sanity check arguments */ + Assert(module); + + /* Disable callback */ + module->callback_enable_mask &= ~(1 << callback_type); +} + +/** + * @} + */ + +/** + * \name Writing and Reading + * @{ + */ +enum status_code usart_write_job( + struct usart_module *const module, + const uint16_t *tx_data); + +enum status_code usart_read_job( + struct usart_module *const module, + uint16_t *const rx_data); + +enum status_code usart_write_buffer_job( + struct usart_module *const module, + uint8_t *tx_data, + uint16_t length); + +enum status_code usart_read_buffer_job( + struct usart_module *const module, + uint8_t *rx_data, + uint16_t length); + +void usart_abort_job( + struct usart_module *const module, + enum usart_transceiver_type transceiver_type); + +enum status_code usart_get_job_status( + struct usart_module *const module, + enum usart_transceiver_type transceiver_type); +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* USART_INTERRUPT_H_INCLUDED */ + diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/system/clock/clock.h b/src/boards/mcu/samr34/ASF/sam0/drivers/system/clock/clock.h new file mode 100644 index 000000000..f75b95104 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/system/clock/clock.h @@ -0,0 +1,43 @@ +/** + * \file + * + * \brief SAM Clock Driver + * + * Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#ifndef SYSTEM_CLOCK_H_INCLUDED +#define SYSTEM_CLOCK_H_INCLUDED + +#include +#include +#include + +#endif /* SYSTEM_CLOCK_H_INCLUDED */ diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/system/clock/clock_samr34/clock.c b/src/boards/mcu/samr34/ASF/sam0/drivers/system/clock/clock_samr34/clock.c new file mode 100644 index 000000000..2960094fd --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/system/clock/clock_samr34/clock.c @@ -0,0 +1,1018 @@ +/** + * \file + * + * \brief SAMR34 Clock Driver + * + * Copyright (c) 2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#include +#include +#include + + +/** + * \internal + * \brief DFLL-specific data container. + */ +struct _system_clock_dfll_config { + uint32_t control; + uint32_t val; + uint32_t mul; +}; + +/** + * \internal + * \brief DPLL-specific data container. + */ +struct _system_clock_dpll_config { + uint32_t frequency; +}; + + +/** + * \internal + * \brief XOSC-specific data container. + */ +struct _system_clock_xosc_config { + uint32_t frequency; +}; + +/** + * \internal + * \brief System clock module data container. + */ +struct _system_clock_module { + volatile struct _system_clock_dfll_config dfll; + volatile struct _system_clock_dpll_config dpll; + + volatile struct _system_clock_xosc_config xosc; + volatile struct _system_clock_xosc_config xosc32k; +}; + +/** + * \internal + * \brief Internal module instance to cache configuration values. + */ +static struct _system_clock_module _system_clock_inst = { + .dfll = { + .control = 0, + .val = 0, + .mul = 0, + }, + .dpll = { + .frequency = 0, + }, + .xosc = { + .frequency = 0, + }, + .xosc32k = { + .frequency = 0, + }, + }; + +/** + * \internal + * \brief Wait for sync to the DFLL control registers. + */ +static inline void _system_dfll_wait_for_sync(void) +{ + while (!(OSCCTRL->STATUS.reg & OSCCTRL_STATUS_DFLLRDY)) { + /* Wait for DFLL sync */ + } +} + +/** + * \internal + * \brief Wait for sync to the OSC32K control registers. + */ +static inline void _system_osc32k_wait_for_sync(void) +{ + while (!(OSC32KCTRL->STATUS.reg & OSC32KCTRL_STATUS_OSC32KRDY)) { + /* Wait for OSC32K sync */ + } +} + +/** + * \internal + * \brief OSC16M frequency selection. + * Frequency selection can be done only when OSC16M is disabled,thus, + * OSCULP32K is temporarily used as a new clocksource for mainclock . + * + */ +static inline void _system_clock_source_osc16m_freq_sel(void) +{ + struct system_gclk_gen_config gclk_conf; + struct system_clock_source_osc16m_config osc16m_conf; + + /* Select OSCULP32K as new clock source for mainclock temporarily */ + system_gclk_gen_get_config_defaults(&gclk_conf); + gclk_conf.source_clock = SYSTEM_CLOCK_SOURCE_ULP32K; + system_gclk_gen_set_config(GCLK_GENERATOR_0, &gclk_conf); + + /* GCLK0 is enabled after POR */ + + /* Disable OSC16M clock*/ + system_clock_source_disable(SYSTEM_CLOCK_SOURCE_OSC16M); + + /* Switch to new frequency selection and enable OSC16M */ + system_clock_source_osc16m_get_config_defaults(&osc16m_conf); + osc16m_conf.fsel = CONF_CLOCK_OSC16M_FREQ_SEL; + osc16m_conf.on_demand = 0; + osc16m_conf.run_in_standby = CONF_CLOCK_OSC16M_RUN_IN_STANDBY; + system_clock_source_osc16m_set_config(&osc16m_conf); + system_clock_source_enable(SYSTEM_CLOCK_SOURCE_OSC16M); + while(!system_clock_source_is_ready(SYSTEM_CLOCK_SOURCE_OSC16M)); + + /* Select OSC16M for mainclock again */ + system_gclk_gen_get_config_defaults(&gclk_conf); + gclk_conf.source_clock = SYSTEM_CLOCK_SOURCE_OSC16M; + system_gclk_gen_set_config(GCLK_GENERATOR_0, &gclk_conf); + if (CONF_CLOCK_OSC16M_ON_DEMAND){ + OSCCTRL->OSC16MCTRL.reg |= OSCCTRL_OSC16MCTRL_ONDEMAND; + } +} + +static inline void _system_clock_source_dfll_set_config_errata_9905(void) +{ + + /* Disable ONDEMAND mode while writing configurations */ + OSCCTRL->DFLLCTRL.reg = OSCCTRL_DFLLCTRL_ENABLE; + _system_dfll_wait_for_sync(); + + OSCCTRL->DFLLMUL.reg = _system_clock_inst.dfll.mul; + OSCCTRL->DFLLVAL.reg = _system_clock_inst.dfll.val; + + /* Write full configuration to DFLL control register */ + OSCCTRL->DFLLCTRL.reg = 0; + _system_dfll_wait_for_sync(); + OSCCTRL->DFLLCTRL.reg = _system_clock_inst.dfll.control; +} + +/** + * \brief Retrieve the frequency of a clock source. + * + * Determines the current operating frequency of a given clock source. + * + * \param[in] clock_source Clock source + * + * \returns Frequency of the given clock source, in Hz. + */ +uint32_t system_clock_source_get_hz( + const enum system_clock_source clock_source) +{ + switch (clock_source) { + case SYSTEM_CLOCK_SOURCE_XOSC: + return _system_clock_inst.xosc.frequency; + + case SYSTEM_CLOCK_SOURCE_OSC16M: + return (OSCCTRL->OSC16MCTRL.bit.FSEL+1)*4000000UL; + + case SYSTEM_CLOCK_SOURCE_OSC32K: + return 32768UL; + + case SYSTEM_CLOCK_SOURCE_ULP32K: + return 32768UL; + + case SYSTEM_CLOCK_SOURCE_XOSC32K: + return _system_clock_inst.xosc32k.frequency; + + case SYSTEM_CLOCK_SOURCE_DFLL: + + /* Check if the DFLL has been configured */ + if (!(_system_clock_inst.dfll.control & OSCCTRL_DFLLCTRL_ENABLE)) + return 0; + + /* Make sure that the DFLL module is ready */ + _system_dfll_wait_for_sync(); + + /* Check if operating in closed loop mode */ + if (_system_clock_inst.dfll.control & OSCCTRL_DFLLCTRL_MODE) { + return system_gclk_chan_get_hz(OSCCTRL_GCLK_ID_DFLL48) * + (_system_clock_inst.dfll.mul & 0xffff); + } + + return 48000000UL; + + case SYSTEM_CLOCK_SOURCE_DPLL: + if (!(OSCCTRL->DPLLCTRLA.reg & OSCCTRL_DPLLCTRLA_ENABLE)) { + return 0; + } + + return _system_clock_inst.dpll.frequency; + + default: + return 0; + } +} + +/** + * \brief Configure the internal OSC16M oscillator clock source. + * + * Configures the 16MHz (nominal) internal RC oscillator with the given + * configuration settings. + * + * \note Frequency selection can be done only when OSC16M is disabled. + * + * \param[in] config OSC16M configuration structure containing the new config + */ +void system_clock_source_osc16m_set_config( + struct system_clock_source_osc16m_config *const config) +{ + OSCCTRL_OSC16MCTRL_Type temp = OSCCTRL->OSC16MCTRL; + + /* Use temporary struct to reduce register access */ + temp.bit.FSEL = config->fsel; + temp.bit.ONDEMAND = config->on_demand; + temp.bit.RUNSTDBY = config->run_in_standby; + + OSCCTRL->OSC16MCTRL = temp; +} + +/** + * \brief Configure the internal OSC32K oscillator clock source. + * + * Configures the 32KHz (nominal) internal RC oscillator with the given + * configuration settings. + * + * \param[in] config OSC32K configuration structure containing the new config + */ +void system_clock_source_osc32k_set_config( + struct system_clock_source_osc32k_config *const config) +{ + OSC32KCTRL_OSC32K_Type temp = OSC32KCTRL->OSC32K; + + + /* Update settings via a temporary struct to reduce register access */ + temp.bit.EN1K = config->enable_1khz_output; + temp.bit.EN32K = config->enable_32khz_output; + temp.bit.STARTUP = config->startup_time; + temp.bit.ONDEMAND = config->on_demand; + temp.bit.RUNSTDBY = config->run_in_standby; + temp.bit.WRTLOCK = config->write_once; + + OSC32KCTRL->OSC32K = temp; +} + +/** + * \brief Configure the internal OSCULP32K oscillator clock source. + * + * Configures the Ultra Low Power 32KHz internal RC oscillator with the given + * configuration settings. + * + * \note The OSCULP32K is enabled by default after a Power On Reset (POR) and + * will always run except during POR. + * + * \param[in] config OSCULP32K configuration structure containing the new config + */ +void system_clock_source_osculp32k_set_config( + struct system_clock_source_osculp32k_config *const config) +{ + OSC32KCTRL_OSCULP32K_Type temp = OSC32KCTRL->OSCULP32K; + /* Update settings via a temporary struct to reduce register access */ + temp.bit.WRTLOCK = config->write_once; + OSC32KCTRL->OSCULP32K = temp; +} + +/** + * \brief Configure the external oscillator clock source. + * + * Configures the external oscillator clock source with the given configuration + * settings. + * + * \param[in] config External oscillator configuration structure containing + * the new config + */ +void system_clock_source_xosc_set_config( + struct system_clock_source_xosc_config *const config) +{ + OSCCTRL_XOSCCTRL_Type temp = OSCCTRL->XOSCCTRL; + + temp.bit.STARTUP = config->startup_time; + + if (config->external_clock == SYSTEM_CLOCK_EXTERNAL_CRYSTAL) { + temp.bit.XTALEN = 1; + } else { + temp.bit.XTALEN = 0; + } + + temp.bit.AMPGC = config->auto_gain_control; + + /* Set gain if automatic gain control is not selected */ + if (!config->auto_gain_control) { + if (config->frequency <= 2000000) { + temp.bit.GAIN = 0; + } else if (config->frequency <= 4000000) { + temp.bit.GAIN = 1; + } else if (config->frequency <= 8000000) { + temp.bit.GAIN = 2; + } else if (config->frequency <= 16000000) { + temp.bit.GAIN = 3; + } else if (config->frequency <= 30000000) { + temp.bit.GAIN = 4; + } + + } + + temp.bit.ONDEMAND = config->on_demand; + temp.bit.RUNSTDBY = config->run_in_standby; + + /* Store XOSC frequency for internal use */ + _system_clock_inst.xosc.frequency = config->frequency; + + OSCCTRL->XOSCCTRL = temp; +} + +/** + * \brief Configure the XOSC32K external 32KHz oscillator clock source. + * + * Configures the external 32KHz oscillator clock source with the given + * configuration settings. + * + * \param[in] config XOSC32K configuration structure containing the new config + */ +void system_clock_source_xosc32k_set_config( + struct system_clock_source_xosc32k_config *const config) +{ + OSC32KCTRL_XOSC32K_Type temp = OSC32KCTRL->XOSC32K; + + temp.bit.STARTUP = config->startup_time; + + if (config->external_clock == SYSTEM_CLOCK_EXTERNAL_CRYSTAL) { + temp.bit.XTALEN = 1; + } else { + temp.bit.XTALEN = 0; + } + + temp.bit.EN1K = config->enable_1khz_output; + temp.bit.EN32K = config->enable_32khz_output; + + temp.bit.ONDEMAND = config->on_demand; + temp.bit.RUNSTDBY = config->run_in_standby; + temp.bit.WRTLOCK = config->write_once; + + /* Cache the new frequency in case the user needs to check the current + * operating frequency later */ + _system_clock_inst.xosc32k.frequency = config->frequency; + + OSC32KCTRL->XOSC32K = temp; +} + +/** + * \brief Configure the DFLL clock source. + * + * Configures the Digital Frequency Locked Loop clock source with the given + * configuration settings. + * + * \note The DFLL will be running when this function returns, as the DFLL module + * needs to be enabled in order to perform the module configuration. + * + * \param[in] config DFLL configuration structure containing the new config + */ +void system_clock_source_dfll_set_config( + struct system_clock_source_dfll_config *const config) +{ + _system_clock_inst.dfll.val = + OSCCTRL_DFLLVAL_COARSE(config->coarse_value) | + OSCCTRL_DFLLVAL_FINE(config->fine_value); + + _system_clock_inst.dfll.control = + (uint32_t)config->wakeup_lock | + (uint32_t)config->stable_tracking | + (uint32_t)config->quick_lock | + (uint32_t)config->chill_cycle | + ((uint32_t)config->on_demand << OSCCTRL_DFLLCTRL_ONDEMAND_Pos) | + ((uint32_t)config->run_in_stanby << OSCCTRL_DFLLCTRL_RUNSTDBY_Pos); + + if (config->loop_mode == SYSTEM_CLOCK_DFLL_LOOP_MODE_CLOSED) { + + _system_clock_inst.dfll.mul = + OSCCTRL_DFLLMUL_CSTEP(config->coarse_max_step) | + OSCCTRL_DFLLMUL_FSTEP(config->fine_max_step) | + OSCCTRL_DFLLMUL_MUL(config->multiply_factor); + + /* Enable the closed loop mode */ + _system_clock_inst.dfll.control |= config->loop_mode; + } + if (config->loop_mode == SYSTEM_CLOCK_DFLL_LOOP_MODE_USB_RECOVERY) { + + _system_clock_inst.dfll.mul = + OSCCTRL_DFLLMUL_CSTEP(config->coarse_max_step) | + OSCCTRL_DFLLMUL_FSTEP(config->fine_max_step) | + OSCCTRL_DFLLMUL_MUL(config->multiply_factor); + + /* Enable the USB recovery mode */ + _system_clock_inst.dfll.control |= config->loop_mode | + OSCCTRL_DFLLCTRL_MODE | OSCCTRL_DFLLCTRL_BPLCKC; + } +} + +/** + * \brief Configure the DPLL clock source. + * + * Configures the Digital Phase-Locked Loop clock source with the given + * configuration settings. + * + * \note The DPLL will be running when this function returns, as the DPLL module + * needs to be enabled in order to perform the module configuration. + * + * \param[in] config DPLL configuration structure containing the new config + */ +void system_clock_source_dpll_set_config( + struct system_clock_source_dpll_config *const config) +{ + + uint32_t tmpldr; + uint8_t tmpldrfrac; + uint32_t refclk; + + refclk = config->reference_frequency; + + /* Only reference clock REF1 can be divided */ + if (config->reference_clock == SYSTEM_CLOCK_SOURCE_DPLL_REFERENCE_CLOCK_XOSC) { + refclk = refclk / (2 * (config->reference_divider + 1)); + } + + /* Calculate LDRFRAC and LDR */ + tmpldr = (config->output_frequency << 4) / refclk; + tmpldrfrac = tmpldr & 0x0f; + tmpldr = (tmpldr >> 4) - 1; + + OSCCTRL->DPLLCTRLA.reg = + ((uint32_t)config->on_demand << OSCCTRL_DPLLCTRLA_ONDEMAND_Pos) | + ((uint32_t)config->run_in_standby << OSCCTRL_DPLLCTRLA_RUNSTDBY_Pos); + + OSCCTRL->DPLLRATIO.reg = + OSCCTRL_DPLLRATIO_LDRFRAC(tmpldrfrac) | + OSCCTRL_DPLLRATIO_LDR(tmpldr); + + while(OSCCTRL->DPLLSYNCBUSY.reg & OSCCTRL_DPLLSYNCBUSY_DPLLRATIO){ + } + + OSCCTRL->DPLLCTRLB.reg = + OSCCTRL_DPLLCTRLB_DIV(config->reference_divider) | + ((uint32_t)config->lock_bypass << OSCCTRL_DPLLCTRLB_LBYPASS_Pos) | + OSCCTRL_DPLLCTRLB_LTIME(config->lock_time) | + OSCCTRL_DPLLCTRLB_REFCLK(config->reference_clock) | + ((uint32_t)config->wake_up_fast << OSCCTRL_DPLLCTRLB_WUF_Pos) | + ((uint32_t)config->low_power_enable << OSCCTRL_DPLLCTRLB_LPEN_Pos) | + OSCCTRL_DPLLCTRLB_FILTER(config->filter); + + OSCCTRL->DPLLPRESC.reg = OSCCTRL_DPLLPRESC_PRESC(config->prescaler); + while(OSCCTRL->DPLLSYNCBUSY.reg & OSCCTRL_DPLLSYNCBUSY_DPLLPRESC){ + } + /* + * Fck = Fckrx * (LDR + 1 + LDRFRAC / 16) / (2^PRESC) + */ + _system_clock_inst.dpll.frequency = + (refclk * (((tmpldr + 1) << 4) + tmpldrfrac)) >> (4 + config->prescaler); +} + +/** + * \brief Writes the calibration values for a given oscillator clock source. + * + * Writes an oscillator calibration value to the given oscillator control + * registers. The acceptable ranges are: + * + * For OSC32K: + * - 7 bits (max. value 128) + * For OSC16MHZ: + * - 8 bits (max. value 255) + * For OSCULP: + * - 5 bits (max. value 32) + * + * \note The frequency range parameter applies only when configuring the 8MHz + * oscillator and will be ignored for the other oscillators. + * + * \param[in] clock_source Clock source to calibrate + * \param[in] calibration_value Calibration value to write + * \param[in] freq_range Frequency range (8MHz oscillator only) + * + * \retval STATUS_OK The calibration value was written + * successfully + * \retval STATUS_ERR_INVALID_ARG The setting is not valid for selected clock + * source + */ +enum status_code system_clock_source_write_calibration( + const enum system_clock_source clock_source, + const uint16_t calibration_value, + const uint8_t freq_select) +{ + switch (clock_source) { + case SYSTEM_CLOCK_SOURCE_OSC16M: + //to enable DSU test mode and add calibration value + return STATUS_OK; + + case SYSTEM_CLOCK_SOURCE_OSC32K: + + if (calibration_value > 128) { + return STATUS_ERR_INVALID_ARG; + } + + _system_osc32k_wait_for_sync(); + OSC32KCTRL->OSC32K.bit.CALIB = calibration_value; + break; + + case SYSTEM_CLOCK_SOURCE_ULP32K: + + if (calibration_value > 32) { + return STATUS_ERR_INVALID_ARG; + } + + OSC32KCTRL->OSCULP32K.bit.CALIB = calibration_value; + break; + + default: + Assert(false); + return STATUS_ERR_INVALID_ARG; + break; + } + + return STATUS_OK; +} + +/** + * \brief Enables a clock source. + * + * Enables a clock source which has been previously configured. + * + * \param[in] clock_source Clock source to enable + * + * \retval STATUS_OK Clock source was enabled successfully and + * is ready + * \retval STATUS_ERR_INVALID_ARG The clock source is not available on this + * device + */ +enum status_code system_clock_source_enable( + const enum system_clock_source clock_source) +{ + switch (clock_source) { + case SYSTEM_CLOCK_SOURCE_OSC16M: + OSCCTRL->OSC16MCTRL.reg |= OSCCTRL_OSC16MCTRL_ENABLE; + return STATUS_OK; + + case SYSTEM_CLOCK_SOURCE_OSC32K: + OSC32KCTRL->OSC32K.reg |= OSC32KCTRL_OSC32K_ENABLE; + break; + + case SYSTEM_CLOCK_SOURCE_XOSC: + OSCCTRL->XOSCCTRL.reg |= OSCCTRL_XOSCCTRL_ENABLE; + break; + + case SYSTEM_CLOCK_SOURCE_XOSC32K: + OSC32KCTRL->XOSC32K.reg |= OSC32KCTRL_XOSC32K_ENABLE; + break; + + case SYSTEM_CLOCK_SOURCE_DFLL: + _system_clock_inst.dfll.control |= OSCCTRL_DFLLCTRL_ENABLE; + _system_clock_source_dfll_set_config_errata_9905(); + break; + + case SYSTEM_CLOCK_SOURCE_DPLL: + OSCCTRL->DPLLCTRLA.reg |= OSCCTRL_DPLLCTRLA_ENABLE; + while(OSCCTRL->DPLLSYNCBUSY.reg & OSCCTRL_DPLLSYNCBUSY_ENABLE){ + } + break; + + case SYSTEM_CLOCK_SOURCE_ULP32K: + /* Always enabled */ + return STATUS_OK; + + default: + Assert(false); + return STATUS_ERR_INVALID_ARG; + } + + return STATUS_OK; +} + +/** + * \brief Disables a clock source. + * + * Disables a clock source that was previously enabled. + * + * \param[in] clock_source Clock source to disable + * + * \retval STATUS_OK Clock source was disabled successfully + * \retval STATUS_ERR_INVALID_ARG An invalid or unavailable clock source was + * given + */ +enum status_code system_clock_source_disable( + const enum system_clock_source clock_source) +{ + switch (clock_source) { + case SYSTEM_CLOCK_SOURCE_OSC16M: + OSCCTRL->OSC16MCTRL.reg &= ~OSCCTRL_OSC16MCTRL_ENABLE; + break; + + case SYSTEM_CLOCK_SOURCE_OSC32K: + OSC32KCTRL->OSC32K.reg &= ~OSC32KCTRL_OSC32K_ENABLE; + break; + + case SYSTEM_CLOCK_SOURCE_XOSC: + OSCCTRL->XOSCCTRL.reg &= ~OSCCTRL_XOSCCTRL_ENABLE; + break; + + case SYSTEM_CLOCK_SOURCE_XOSC32K: + OSC32KCTRL->XOSC32K.reg &= ~OSC32KCTRL_XOSC32K_ENABLE; + break; + + case SYSTEM_CLOCK_SOURCE_DFLL: + _system_clock_inst.dfll.control &= ~OSCCTRL_DFLLCTRL_ENABLE; + OSCCTRL->DFLLCTRL.reg = _system_clock_inst.dfll.control; + break; + case SYSTEM_CLOCK_SOURCE_DPLL: + OSCCTRL->DPLLCTRLA.reg &= ~OSCCTRL_DPLLCTRLA_ENABLE; + break; + case SYSTEM_CLOCK_SOURCE_ULP32K: + /* Not possible to disable */ + + default: + Assert(false); + return STATUS_ERR_INVALID_ARG; + + } + + return STATUS_OK; +} + +/** + * \brief Checks if a clock source is ready. + * + * Checks if a given clock source is ready to be used. + * + * \param[in] clock_source Clock source to check if ready + * + * \returns Ready state of the given clock source. + * + * \retval true Clock source is enabled and ready + * \retval false Clock source is disabled or not yet ready + */ +bool system_clock_source_is_ready( + const enum system_clock_source clock_source) +{ + uint32_t mask = 0; + + switch (clock_source) { + case SYSTEM_CLOCK_SOURCE_OSC16M: + mask = OSCCTRL_STATUS_OSC16MRDY; + return ((OSCCTRL->STATUS.reg & mask) == mask); + + case SYSTEM_CLOCK_SOURCE_OSC32K: + mask = OSC32KCTRL_STATUS_OSC32KRDY; + return ((OSC32KCTRL->STATUS.reg & mask) == mask); + + case SYSTEM_CLOCK_SOURCE_XOSC: + mask = OSCCTRL_STATUS_XOSCRDY; + return ((OSCCTRL->STATUS.reg & mask) == mask); + + case SYSTEM_CLOCK_SOURCE_XOSC32K: + mask = OSC32KCTRL_STATUS_XOSC32KRDY; + return ((OSC32KCTRL->STATUS.reg & mask) == mask); + + case SYSTEM_CLOCK_SOURCE_DFLL: + if (CONF_CLOCK_DFLL_LOOP_MODE == SYSTEM_CLOCK_DFLL_LOOP_MODE_CLOSED) { + mask = (OSCCTRL_STATUS_DFLLRDY | + OSCCTRL_STATUS_DFLLLCKF | OSCCTRL_STATUS_DFLLLCKC); + } else { + mask = OSCCTRL_STATUS_DFLLRDY; + } + return ((OSCCTRL->STATUS.reg & mask) == mask); + + case SYSTEM_CLOCK_SOURCE_DPLL: + return ((OSCCTRL->DPLLSTATUS.reg & + (OSCCTRL_DPLLSTATUS_CLKRDY | OSCCTRL_DPLLSTATUS_LOCK)) == + (OSCCTRL_DPLLSTATUS_CLKRDY | OSCCTRL_DPLLSTATUS_LOCK)); + case SYSTEM_CLOCK_SOURCE_ULP32K: + /* Not possible to disable */ + return true; + + default: + return false; + } +} + +/* Include some checks for conf_clocks.h validation */ +#include "clock_config_check.h" + +#if !defined(__DOXYGEN__) +/** \internal + * + * Configures a Generic Clock Generator with the configuration from \c conf_clocks.h. + */ +# define _CONF_CLOCK_GCLK_CONFIG(n, unused) \ + if (CONF_CLOCK_GCLK_##n##_ENABLE == true) { \ + struct system_gclk_gen_config gclk_conf; \ + system_gclk_gen_get_config_defaults(&gclk_conf); \ + gclk_conf.source_clock = CONF_CLOCK_GCLK_##n##_CLOCK_SOURCE; \ + gclk_conf.division_factor = CONF_CLOCK_GCLK_##n##_PRESCALER; \ + gclk_conf.run_in_standby = CONF_CLOCK_GCLK_##n##_RUN_IN_STANDBY; \ + gclk_conf.output_enable = CONF_CLOCK_GCLK_##n##_OUTPUT_ENABLE; \ + system_gclk_gen_set_config(GCLK_GENERATOR_##n, &gclk_conf); \ + system_gclk_gen_enable(GCLK_GENERATOR_##n); \ + } + +/** \internal + * + * Configures a Generic Clock Generator with the configuration from \c conf_clocks.h, + * provided that it is not the main Generic Clock Generator channel. + */ +# define _CONF_CLOCK_GCLK_CONFIG_NONMAIN(n, unused) \ + if (n > 0) { _CONF_CLOCK_GCLK_CONFIG(n, unused); } +#endif + +/** + * \brief Initialize clock system based on the configuration in conf_clocks.h. + * + * This function will apply the settings in conf_clocks.h when run from the user + * application. All clock sources and GCLK generators are running when this function + * returns. + * + * \note OSC16M is always enabled and if user selects other clocks for GCLK generators, + * the OSC16M default enable can be disabled after system_clock_init. Make sure the + * clock switches successfully before disabling OSC8M. + */ +void system_clock_init(void) +{ + /* Various bits in the INTFLAG register can be set to one at startup. + This will ensure that these bits are cleared */ + OSCCTRL->INTFLAG.reg = OSCCTRL_INTFLAG_DFLLRDY; + SUPC->INTFLAG.reg = SUPC_INTFLAG_BOD33RDY | SUPC_INTFLAG_BOD33DET; + + system_flash_set_waitstates(CONF_CLOCK_FLASH_WAIT_STATES); + + /* Switch to PL2 to be sure configuration of GCLK0 is safe */ + system_switch_performance_level(SYSTEM_PERFORMANCE_LEVEL_2); + + /* XOSC */ +#if CONF_CLOCK_XOSC_ENABLE == true + struct system_clock_source_xosc_config xosc_conf; + system_clock_source_xosc_get_config_defaults(&xosc_conf); + + xosc_conf.external_clock = CONF_CLOCK_XOSC_EXTERNAL_CRYSTAL; + xosc_conf.startup_time = CONF_CLOCK_XOSC_STARTUP_TIME; + xosc_conf.auto_gain_control = CONF_CLOCK_XOSC_AUTO_GAIN_CONTROL; + xosc_conf.frequency = CONF_CLOCK_XOSC_EXTERNAL_FREQUENCY; + xosc_conf.on_demand = CONF_CLOCK_XOSC_ON_DEMAND; + xosc_conf.run_in_standby = CONF_CLOCK_XOSC_RUN_IN_STANDBY; + + system_clock_source_xosc_set_config(&xosc_conf); + system_clock_source_enable(SYSTEM_CLOCK_SOURCE_XOSC); +#endif + + /* XOSC32K */ +#if CONF_CLOCK_XOSC32K_ENABLE == true + struct system_clock_source_xosc32k_config xosc32k_conf; + system_clock_source_xosc32k_get_config_defaults(&xosc32k_conf); + + xosc32k_conf.frequency = 32768UL; + xosc32k_conf.external_clock = CONF_CLOCK_XOSC32K_EXTERNAL_CRYSTAL; + xosc32k_conf.startup_time = CONF_CLOCK_XOSC32K_STARTUP_TIME; + xosc32k_conf.enable_1khz_output = CONF_CLOCK_XOSC32K_ENABLE_1KHZ_OUPUT; + xosc32k_conf.enable_32khz_output = CONF_CLOCK_XOSC32K_ENABLE_32KHZ_OUTPUT; + xosc32k_conf.on_demand = false; + xosc32k_conf.run_in_standby = CONF_CLOCK_XOSC32K_RUN_IN_STANDBY; + + system_clock_source_xosc32k_set_config(&xosc32k_conf); + system_clock_source_enable(SYSTEM_CLOCK_SOURCE_XOSC32K); + while(!system_clock_source_is_ready(SYSTEM_CLOCK_SOURCE_XOSC32K)); + if (CONF_CLOCK_XOSC32K_ON_DEMAND) { + OSC32KCTRL->XOSC32K.bit.ONDEMAND = 1; + } +#endif + + /* OSCK32K */ +#if CONF_CLOCK_OSC32K_ENABLE == true + + struct system_clock_source_osc32k_config osc32k_conf; + system_clock_source_osc32k_get_config_defaults(&osc32k_conf); + + osc32k_conf.startup_time = CONF_CLOCK_OSC32K_STARTUP_TIME; + osc32k_conf.enable_1khz_output = CONF_CLOCK_OSC32K_ENABLE_1KHZ_OUTPUT; + osc32k_conf.enable_32khz_output = CONF_CLOCK_OSC32K_ENABLE_32KHZ_OUTPUT; + osc32k_conf.on_demand = CONF_CLOCK_OSC32K_ON_DEMAND; + osc32k_conf.run_in_standby = CONF_CLOCK_OSC32K_RUN_IN_STANDBY; + + system_clock_source_osc32k_set_config(&osc32k_conf); + system_clock_source_enable(SYSTEM_CLOCK_SOURCE_OSC32K); +#endif + + /* OSC16M */ + if (CONF_CLOCK_OSC16M_FREQ_SEL == SYSTEM_OSC16M_4M){ + OSCCTRL->OSC16MCTRL.bit.ONDEMAND = CONF_CLOCK_OSC16M_ON_DEMAND ; + OSCCTRL->OSC16MCTRL.bit.RUNSTDBY = CONF_CLOCK_OSC16M_RUN_IN_STANDBY; + } else { + _system_clock_source_osc16m_freq_sel(); + } + + /* DFLL Config (Open and Closed Loop) */ +#if CONF_CLOCK_DFLL_ENABLE == true + struct system_clock_source_dfll_config dfll_conf; + system_clock_source_dfll_get_config_defaults(&dfll_conf); + + dfll_conf.loop_mode = CONF_CLOCK_DFLL_LOOP_MODE; + dfll_conf.on_demand = false; + dfll_conf.run_in_stanby = CONF_CLOCK_DFLL_RUN_IN_STANDBY; + + /* Using DFLL48M COARSE CAL value from NVM Software Calibration Area Mapping + in DFLL.COARSE helps to output a frequency close to 48 MHz.*/ +#define NVM_DFLL_COARSE_POS 26 /* DFLL48M Coarse calibration value bit position.*/ +#define NVM_DFLL_COARSE_SIZE 6 /* DFLL48M Coarse calibration value bit size.*/ + + uint32_t coarse =( *((uint32_t *)(NVMCTRL_OTP5) + + (NVM_DFLL_COARSE_POS / 32)) + >> (NVM_DFLL_COARSE_POS % 32)) + & ((1 << NVM_DFLL_COARSE_SIZE) - 1); + /* In some revision chip, the Calibration value is not correct */ + if (coarse == 0x3f) { + coarse = 0x1f; + } + + dfll_conf.coarse_value = coarse; + + if (CONF_CLOCK_DFLL_LOOP_MODE == SYSTEM_CLOCK_DFLL_LOOP_MODE_OPEN) { + dfll_conf.fine_value = CONF_CLOCK_DFLL_FINE_VALUE; + } + +# if CONF_CLOCK_DFLL_QUICK_LOCK == true + dfll_conf.quick_lock = SYSTEM_CLOCK_DFLL_QUICK_LOCK_ENABLE; +# else + dfll_conf.quick_lock = SYSTEM_CLOCK_DFLL_QUICK_LOCK_DISABLE; +# endif + +# if CONF_CLOCK_DFLL_TRACK_AFTER_FINE_LOCK == true + dfll_conf.stable_tracking = SYSTEM_CLOCK_DFLL_STABLE_TRACKING_TRACK_AFTER_LOCK; +# else + dfll_conf.stable_tracking = SYSTEM_CLOCK_DFLL_STABLE_TRACKING_FIX_AFTER_LOCK; +# endif + +# if CONF_CLOCK_DFLL_KEEP_LOCK_ON_WAKEUP == true + dfll_conf.wakeup_lock = SYSTEM_CLOCK_DFLL_WAKEUP_LOCK_KEEP; +# else + dfll_conf.wakeup_lock = SYSTEM_CLOCK_DFLL_WAKEUP_LOCK_LOSE; +# endif + +# if CONF_CLOCK_DFLL_ENABLE_CHILL_CYCLE == true + dfll_conf.chill_cycle = SYSTEM_CLOCK_DFLL_CHILL_CYCLE_ENABLE; +# else + dfll_conf.chill_cycle = SYSTEM_CLOCK_DFLL_CHILL_CYCLE_DISABLE; +# endif + + if (CONF_CLOCK_DFLL_LOOP_MODE == SYSTEM_CLOCK_DFLL_LOOP_MODE_CLOSED) { + dfll_conf.multiply_factor = CONF_CLOCK_DFLL_MULTIPLY_FACTOR; + } + + dfll_conf.coarse_max_step = CONF_CLOCK_DFLL_MAX_COARSE_STEP_SIZE; + dfll_conf.fine_max_step = CONF_CLOCK_DFLL_MAX_FINE_STEP_SIZE; + + if (CONF_CLOCK_DFLL_LOOP_MODE == SYSTEM_CLOCK_DFLL_LOOP_MODE_USB_RECOVERY) { + dfll_conf.fine_max_step = 10; + dfll_conf.fine_value = 0x1ff; + dfll_conf.quick_lock = SYSTEM_CLOCK_DFLL_QUICK_LOCK_ENABLE; + dfll_conf.stable_tracking = SYSTEM_CLOCK_DFLL_STABLE_TRACKING_TRACK_AFTER_LOCK; + dfll_conf.wakeup_lock = SYSTEM_CLOCK_DFLL_WAKEUP_LOCK_KEEP; + dfll_conf.chill_cycle = SYSTEM_CLOCK_DFLL_CHILL_CYCLE_DISABLE; + + dfll_conf.multiply_factor = 48000; + } + + system_clock_source_dfll_set_config(&dfll_conf); +#endif + + /* GCLK */ +#if CONF_CLOCK_CONFIGURE_GCLK == true + system_gclk_init(); + + /* Configure all GCLK generators except for the main generator, which + * is configured later after all other clock systems are set up */ + MREPEAT(GCLK_GEN_NUM, _CONF_CLOCK_GCLK_CONFIG_NONMAIN, ~); +# if CONF_CLOCK_DFLL_ENABLE == true + /* Enable DFLL reference clock if in closed loop mode */ + if (CONF_CLOCK_DFLL_LOOP_MODE == SYSTEM_CLOCK_DFLL_LOOP_MODE_CLOSED) { + struct system_gclk_chan_config dfll_gclk_chan_conf; + + system_gclk_chan_get_config_defaults(&dfll_gclk_chan_conf); + dfll_gclk_chan_conf.source_generator = CONF_CLOCK_DFLL_SOURCE_GCLK_GENERATOR; + system_gclk_chan_set_config(OSCCTRL_GCLK_ID_DFLL48, &dfll_gclk_chan_conf); + system_gclk_chan_enable(OSCCTRL_GCLK_ID_DFLL48); + } +# endif + +# if CONF_CLOCK_DPLL_ENABLE == true + /* Enable DPLL internal lock timer and reference clock */ + struct system_gclk_chan_config dpll_gclk_chan_conf; + system_gclk_chan_get_config_defaults(&dpll_gclk_chan_conf); + if (CONF_CLOCK_DPLL_LOCK_TIME != SYSTEM_CLOCK_SOURCE_DPLL_LOCK_TIME_DEFAULT) { + dpll_gclk_chan_conf.source_generator = CONF_CLOCK_DPLL_LOCK_GCLK_GENERATOR; + system_gclk_chan_set_config(OSCCTRL_GCLK_ID_FDPLL32K, &dpll_gclk_chan_conf); + system_gclk_chan_enable(OSCCTRL_GCLK_ID_FDPLL32K); + } + + if (CONF_CLOCK_DPLL_REFERENCE_CLOCK == SYSTEM_CLOCK_SOURCE_DPLL_REFERENCE_CLOCK_GCLK) { + dpll_gclk_chan_conf.source_generator = CONF_CLOCK_DPLL_REFERENCE_GCLK_GENERATOR; + system_gclk_chan_set_config(OSCCTRL_GCLK_ID_FDPLL, &dpll_gclk_chan_conf); + system_gclk_chan_enable(OSCCTRL_GCLK_ID_FDPLL); + } +# endif +#endif + + /* DFLL Enable (Open and Closed Loop) */ +#if CONF_CLOCK_DFLL_ENABLE == true + system_clock_source_enable(SYSTEM_CLOCK_SOURCE_DFLL); + while(!system_clock_source_is_ready(SYSTEM_CLOCK_SOURCE_DFLL)); + if (CONF_CLOCK_DFLL_ON_DEMAND) { + OSCCTRL->DFLLCTRL.bit.ONDEMAND = 1; + } +#endif + + /* DPLL */ +# if (CONF_CLOCK_DPLL_ENABLE == true) + + /* Enable DPLL reference clock */ + if (CONF_CLOCK_DPLL_REFERENCE_CLOCK == SYSTEM_CLOCK_SOURCE_DPLL_REFERENCE_CLOCK_XOSC32K) { + /* XOSC32K should have been enabled for GCLK_XOSC32 */ + Assert(CONF_CLOCK_XOSC32K_ENABLE); + } else if (CONF_CLOCK_DPLL_REFERENCE_CLOCK == SYSTEM_CLOCK_SOURCE_DPLL_REFERENCE_CLOCK_XOSC) { + /* XOSC should have been enabled for GCLK_XOSC */ + Assert(CONF_CLOCK_XOSC_ENABLE); + } + else if (CONF_CLOCK_DPLL_REFERENCE_CLOCK == SYSTEM_CLOCK_SOURCE_DPLL_REFERENCE_CLOCK_GCLK) { + /* GCLK should have been enabled */ + Assert(CONF_CLOCK_CONFIGURE_GCLK); + } + else { + Assert(false); + } + + struct system_clock_source_dpll_config dpll_config; + system_clock_source_dpll_get_config_defaults(&dpll_config); + + dpll_config.on_demand = false; + dpll_config.run_in_standby = CONF_CLOCK_DPLL_RUN_IN_STANDBY; + dpll_config.lock_bypass = CONF_CLOCK_DPLL_LOCK_BYPASS; + dpll_config.wake_up_fast = CONF_CLOCK_DPLL_WAKE_UP_FAST; + dpll_config.low_power_enable = CONF_CLOCK_DPLL_LOW_POWER_ENABLE; + + dpll_config.filter = CONF_CLOCK_DPLL_FILTER; + dpll_config.lock_time = CONF_CLOCK_DPLL_LOCK_TIME; + + dpll_config.reference_clock = CONF_CLOCK_DPLL_REFERENCE_CLOCK; + dpll_config.reference_frequency = CONF_CLOCK_DPLL_REFERENCE_FREQUENCY; + dpll_config.reference_divider = CONF_CLOCK_DPLL_REFERENCE_DIVIDER; + dpll_config.output_frequency = CONF_CLOCK_DPLL_OUTPUT_FREQUENCY; + dpll_config.prescaler = CONF_CLOCK_DPLL_PRESCALER; + + system_clock_source_dpll_set_config(&dpll_config); + system_clock_source_enable(SYSTEM_CLOCK_SOURCE_DPLL); + while(!system_clock_source_is_ready(SYSTEM_CLOCK_SOURCE_DPLL)); + if (CONF_CLOCK_DPLL_ON_DEMAND) { + OSCCTRL->DPLLCTRLA.bit.ONDEMAND = 1; + } + +# endif + + /* CPU and BUS clocks */ + system_backup_clock_set_divider(CONF_CLOCK_BACKUP_DIVIDER); + system_low_power_clock_set_divider(CONF_CLOCK_LOW_POWER_DIVIDER); + system_cpu_clock_set_divider(CONF_CLOCK_CPU_DIVIDER); + system_main_clock_set_failure_detect(CONF_CLOCK_CPU_CLOCK_FAILURE_DETECT); + + /* GCLK 0 */ +#if CONF_CLOCK_CONFIGURE_GCLK == true + /* Configure the main GCLK last as it might depend on other generators */ + _CONF_CLOCK_GCLK_CONFIG(0, ~); +#endif + + /* If CPU frequency is less than 12MHz, scale down performance level to PL0 */ + uint32_t cpu_freq = system_cpu_clock_get_hz(); + if (cpu_freq <= 12000000) { + system_switch_performance_level(SYSTEM_PERFORMANCE_LEVEL_0); + } +} diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/system/clock/clock_samr34/clock_config_check.h b/src/boards/mcu/samr34/ASF/sam0/drivers/system/clock/clock_samr34/clock_config_check.h new file mode 100644 index 000000000..46cf388b2 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/system/clock/clock_samr34/clock_config_check.h @@ -0,0 +1,449 @@ +/** + * \file + * + * \brief SAMR34 Clock Driver + * + * Copyright (c) 2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#ifndef CLOCK_CONFIG_CHECK_H +# define CLOCK_CONFIG_CHECK_H + +#if !defined(CONF_CLOCK_CPU_CLOCK_FAILURE_DETECT) +# error CONF_CLOCK_CPU_CLOCK_FAILURE_DETECT not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_FLASH_WAIT_STATES) +# error CONF_CLOCK_FLASH_WAIT_STATES not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_CPU_DIVIDER) +# error CONF_CLOCK_CPU_DIVIDER not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_LOW_POWER_DIVIDER) +# error CONF_CLOCK_LOW_POWER_DIVIDER not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_BACKUP_DIVIDER) +# error CONF_CLOCK_BACK_DIVIDER not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_OSC16M_FREQ_SEL) +# error CONF_CLOCK_OSC16M_FREQ_SEL not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_OSC16M_ON_DEMAND) +# error CONF_CLOCK_OSC16M_ON_DEMAND not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_OSC16M_RUN_IN_STANDBY) +# error CONF_CLOCK_OSC16M_RUN_IN_STANDBY not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_XOSC_ENABLE) +# error CONF_CLOCK_XOSC_ENABLE not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_XOSC_EXTERNAL_CRYSTAL) +# error CONF_CLOCK_XOSC_EXTERNAL_CRYSTAL not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_XOSC_EXTERNAL_FREQUENCY) +# error CONF_CLOCK_XOSC_EXTERNAL_FREQUENCY not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_XOSC_STARTUP_TIME) +# error CONF_CLOCK_XOSC_STARTUP_TIME not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_XOSC_AUTO_GAIN_CONTROL) +# error CONF_CLOCK_XOSC_AUTO_GAIN_CONTROL not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_XOSC_ON_DEMAND) +# error CONF_CLOCK_XOSC_ON_DEMAND not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_XOSC_RUN_IN_STANDBY) +# error CONF_CLOCK_XOSC_RUN_IN_STANDBY not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_XOSC32K_ENABLE) +# error CONF_CLOCK_XOSC32K_ENABLE not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_XOSC32K_EXTERNAL_CRYSTAL) +# error CONF_CLOCK_XOSC32K_EXTERNAL_CRYSTAL not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_XOSC32K_STARTUP_TIME) +# error CONF_CLOCK_XOSC32K_STARTUP_TIME not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_XOSC32K_ENABLE_1KHZ_OUPUT) +# error CONF_CLOCK_XOSC32K_ENABLE_1KHZ_OUPUT not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_XOSC32K_ENABLE_32KHZ_OUTPUT) +# error CONF_CLOCK_XOSC32K_ENABLE_32KHZ_OUTPUT not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_XOSC32K_ON_DEMAND) +# error CONF_CLOCK_XOSC32K_ON_DEMAND not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_XOSC32K_RUN_IN_STANDBY) +# error CONF_CLOCK_XOSC32K_RUN_IN_STANDBY not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_OSC32K_ENABLE) +# error CONF_CLOCK_OSC32K_ENABLE not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_OSC32K_STARTUP_TIME) +# error CONF_CLOCK_OSC32K_STARTUP_TIME not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_OSC32K_ENABLE_1KHZ_OUTPUT) +# error CONF_CLOCK_OSC32K_ENABLE_1KHZ_OUTPUT not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_OSC32K_ENABLE_32KHZ_OUTPUT) +# error CONF_CLOCK_OSC32K_ENABLE_32KHZ_OUTPUT not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_OSC32K_ON_DEMAND) +# error CONF_CLOCK_OSC32K_ON_DEMAND not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_OSC32K_RUN_IN_STANDBY) +# error CONF_CLOCK_OSC32K_RUN_IN_STANDBY not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_DFLL_ENABLE) +# error CONF_CLOCK_DFLL_ENABLE not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_DFLL_LOOP_MODE) +# error CONF_CLOCK_DFLL_LOOP_MODE not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_DFLL_ON_DEMAND) +# error CONF_CLOCK_DFLL_ON_DEMAND not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_DFLL_FINE_VALUE) +# error CONF_CLOCK_DFLL_FINE_VALUE not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_DFLL_RUN_IN_STANDBY) +# error CONF_CLOCK_DFLL_RUN_IN_STANDBY not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_DFLL_SOURCE_GCLK_GENERATOR) +# error CONF_CLOCK_DFLL_SOURCE_GCLK_GENERATOR not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_DFLL_MULTIPLY_FACTOR) +# error CONF_CLOCK_DFLL_MULTIPLY_FACTOR not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_DFLL_QUICK_LOCK) +# error CONF_CLOCK_DFLL_QUICK_LOCK not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_DFLL_TRACK_AFTER_FINE_LOCK) +# error CONF_CLOCK_DFLL_TRACK_AFTER_FINE_LOCK not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_DFLL_KEEP_LOCK_ON_WAKEUP) +# error CONF_CLOCK_DFLL_KEEP_LOCK_ON_WAKEUP not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_DFLL_ENABLE_CHILL_CYCLE) +# error CONF_CLOCK_DFLL_ENABLE_CHILL_CYCLE not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_DFLL_MAX_COARSE_STEP_SIZE) +# error CONF_CLOCK_DFLL_MAX_COARSE_STEP_SIZE not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_DFLL_MAX_FINE_STEP_SIZE) +# error CONF_CLOCK_DFLL_MAX_FINE_STEP_SIZE not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_DPLL_ENABLE) +# error CONF_CLOCK_DPLL_ENABLE not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_DPLL_ON_DEMAND) +# error CONF_CLOCK_DPLL_ON_DEMAND not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_DPLL_RUN_IN_STANDBY) +# error CONF_CLOCK_DPLL_RUN_IN_STANDBY not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_DPLL_LOCK_BYPASS) +# error CONF_CLOCK_DPLL_LOCK_BYPASS not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_DPLL_WAKE_UP_FAST) +# error CONF_CLOCK_DPLL_WAKE_UP_FAST not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_DPLL_LOW_POWER_ENABLE) +# error CONF_CLOCK_DPLL_LOW_POWER_ENABLE not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_DPLL_LOCK_TIME) +# error CONF_CLOCK_DPLL_LOCK_TIME not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_DPLL_REFERENCE_CLOCK) +# error CONF_CLOCK_DPLL_REFERENCE_CLOCK not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_DPLL_FILTER) +# error CONF_CLOCK_DPLL_FILTER not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_DPLL_REFERENCE_FREQUENCY) +# error CONF_CLOCK_DPLL_REFERENCE_FREQUENCY not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_DPLL_REFERENCE_DIVIDER) +# error CONF_CLOCK_DPLL_REFERENCE_DIVIDER not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_DPLL_OUTPUT_FREQUENCY) +# error CONF_CLOCK_DPLL_OUTPUT_FREQUENCY not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_DPLL_PRESCALER) +# error CONF_CLOCK_DPLL_PRESCALER not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_DPLL_REFERENCE_GCLK_GENERATOR) +# error CONF_CLOCK_DPLL_REFERENCE_GCLK_GENERATOR not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_DPLL_LOCK_GCLK_GENERATOR) +# error CONF_CLOCK_DPLL_LOCK_GCLK_GENERATOR not defined in conf_clocks.h +#endif + + +#if !defined(CONF_CLOCK_CONFIGURE_GCLK) +# error CONF_CLOCK_CONFIGURE_GCLK not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_0_ENABLE) +# error CONF_CLOCK_GCLK_0_ENABLE not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_0_RUN_IN_STANDBY) +# error CONF_CLOCK_GCLK_0_RUN_IN_STANDBY not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_0_CLOCK_SOURCE) +# error CONF_CLOCK_GCLK_0_CLOCK_SOURCE not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_0_PRESCALER) +# error CONF_CLOCK_GCLK_0_PRESCALER not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_0_OUTPUT_ENABLE) +# error CONF_CLOCK_GCLK_0_OUTPUT_ENABLE not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_1_ENABLE) +# error CONF_CLOCK_GCLK_1_ENABLE not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_1_RUN_IN_STANDBY) +# error CONF_CLOCK_GCLK_1_RUN_IN_STANDBY not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_1_CLOCK_SOURCE) +# error CONF_CLOCK_GCLK_1_CLOCK_SOURCE not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_1_PRESCALER) +# error CONF_CLOCK_GCLK_1_PRESCALER not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_1_OUTPUT_ENABLE) +# error CONF_CLOCK_GCLK_1_OUTPUT_ENABLE not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_2_ENABLE) +# error CONF_CLOCK_GCLK_2_ENABLE not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_2_RUN_IN_STANDBY) +# error CONF_CLOCK_GCLK_2_RUN_IN_STANDBY not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_2_CLOCK_SOURCE) +# error CONF_CLOCK_GCLK_2_CLOCK_SOURCE not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_2_PRESCALER) +# error CONF_CLOCK_GCLK_2_PRESCALER not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_2_OUTPUT_ENABLE) +# error CONF_CLOCK_GCLK_2_OUTPUT_ENABLE not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_3_ENABLE) +# error CONF_CLOCK_GCLK_3_ENABLE not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_3_RUN_IN_STANDBY) +# error CONF_CLOCK_GCLK_3_RUN_IN_STANDBY not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_3_CLOCK_SOURCE) +# error CONF_CLOCK_GCLK_3_CLOCK_SOURCE not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_3_PRESCALER) +# error CONF_CLOCK_GCLK_3_PRESCALER not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_3_OUTPUT_ENABLE) +# error CONF_CLOCK_GCLK_3_OUTPUT_ENABLE not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_4_ENABLE) +# error CONF_CLOCK_GCLK_4_ENABLE not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_4_RUN_IN_STANDBY) +# error CONF_CLOCK_GCLK_4_RUN_IN_STANDBY not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_4_CLOCK_SOURCE) +# error CONF_CLOCK_GCLK_4_CLOCK_SOURCE not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_4_PRESCALER) +# error CONF_CLOCK_GCLK_4_PRESCALER not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_4_OUTPUT_ENABLE) +# error CONF_CLOCK_GCLK_4_OUTPUT_ENABLE not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_5_ENABLE) +# error CONF_CLOCK_GCLK_5_ENABLE not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_5_RUN_IN_STANDBY) +# error CONF_CLOCK_GCLK_5_RUN_IN_STANDBY not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_5_CLOCK_SOURCE) +# error CONF_CLOCK_GCLK_5_CLOCK_SOURCE not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_5_PRESCALER) +# error CONF_CLOCK_GCLK_5_PRESCALER not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_5_OUTPUT_ENABLE) +# error CONF_CLOCK_GCLK_5_OUTPUT_ENABLE not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_6_ENABLE) +# error CONF_CLOCK_GCLK_6_ENABLE not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_6_RUN_IN_STANDBY) +# error CONF_CLOCK_GCLK_6_RUN_IN_STANDBY not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_6_CLOCK_SOURCE) +# error CONF_CLOCK_GCLK_6_CLOCK_SOURCE not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_6_PRESCALER) +# error CONF_CLOCK_GCLK_6_PRESCALER not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_6_OUTPUT_ENABLE) +# error CONF_CLOCK_GCLK_6_OUTPUT_ENABLE not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_7_ENABLE) +# error CONF_CLOCK_GCLK_7_ENABLE not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_7_RUN_IN_STANDBY) +# error CONF_CLOCK_GCLK_7_RUN_IN_STANDBY not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_7_CLOCK_SOURCE) +# error CONF_CLOCK_GCLK_7_CLOCK_SOURCE not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_7_PRESCALER) +# error CONF_CLOCK_GCLK_7_PRESCALER not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_7_OUTPUT_ENABLE) +# error CONF_CLOCK_GCLK_7_OUTPUT_ENABLE not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_8_ENABLE) +# error CONF_CLOCK_GCLK_8_ENABLE not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_8_RUN_IN_STANDBY) +# error CONF_CLOCK_GCLK_8_RUN_IN_STANDBY not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_8_CLOCK_SOURCE) +# error CONF_CLOCK_GCLK_8_CLOCK_SOURCE not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_8_PRESCALER) +# error CONF_CLOCK_GCLK_8_PRESCALER not defined in conf_clocks.h +#endif + +#if !defined(CONF_CLOCK_GCLK_8_OUTPUT_ENABLE) +# error CONF_CLOCK_GCLK_8_OUTPUT_ENABLE not defined in conf_clocks.h +#endif + +#endif /* CLOCK_CONFIG_CHECK_H */ diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/system/clock/clock_samr34/clock_feature.h b/src/boards/mcu/samr34/ASF/sam0/drivers/system/clock/clock_samr34/clock_feature.h new file mode 100644 index 000000000..3660974b6 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/system/clock/clock_samr34/clock_feature.h @@ -0,0 +1,1479 @@ +/** + * \file + * + * \brief SAMR34 Clock Driver + * + * Copyright (c) 2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#ifndef SYSTEM_CLOCK_FEATURE_H_INCLUDED +#define SYSTEM_CLOCK_FEATURE_H_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup asfdoc_sam0_system_clock_group SAM System Clock Management (SYSTEM CLOCK) Driver + * + * This driver for Atmel® | SMART ARM®-based microcontrollers provides an interface for the configuration + * and management of the device's clocking related functions. This includes + * the various clock sources, bus clocks, and generic clocks within the device, + * with functions to manage the enabling, disabling, source selection, and + * prescaling of clocks to various internal peripherals. + * + * The following peripherals are used by this module: + * + * - GCLK (Generic Clock Management) + * - PM (Power Management) + * - OSCCTRL (Oscillators Controller) + * - OSC32KCTRL (32K Oscillators Controller) + * - MCLK (Main Clock) + * + * The following devices can use this module: + * - Atmel | SMART SAM R34 + * + * The outline of this documentation is as follows: + * - \ref asfdoc_sam0_system_clock_prerequisites + * - \ref asfdoc_sam0_system_clock_module_overview + * - \ref asfdoc_sam0_system_clock_special_considerations + * - \ref asfdoc_sam0_system_clock_extra_info + * - \ref asfdoc_sam0_system_clock_examples + * - \ref asfdoc_sam0_system_clock_api_overview + * + * + * \section asfdoc_sam0_system_clock_prerequisites Prerequisites + * + * There are no prerequisites for this module. + * + * + * \section asfdoc_sam0_system_clock_module_overview Module Overview + * The SAM devices contain a sophisticated clocking system, which is designed + * to give the maximum flexibility to the user application. This system allows + * a system designer to tune the performance and power consumption of the device + * in a dynamic manner, to achieve the best trade-off between the two for a + * particular application. + * + * This driver provides a set of functions for the configuration and management + * of the various clock related functionalities within the device. + * + * + * \subsection asfdoc_sam0_system_clock_module_overview_clock_sources Clock Sources + * The SAM devices have a number of master clock source modules, each of + * which being capable of producing a stabilized output frequency which can then + * be fed into the various peripherals and modules within the device. + * + * Possible clock source modules include internal R/C oscillators, internal + * DFLL modules, as well as external crystal oscillators and/or clock inputs. + * + * \subsection asfdoc_sam0_system_clock_module_overview_cpu_clock CPU / Bus Clocks + * The CPU and AHB/APBx buses are clocked by the same physical clock source + * (referred in this module as the Main Clock). + * The CPU and bus clocks are divided into a number of clock domains. Each clock domain can + * run at different frequencies. + * + * There are three clock domains: + * + * - CPU Clock Domain + * - Low Power Clock Domain(LP Clock Domain) + * - Backup Clock Domain(BUP Clock Domain) + * + * Each clock domain (CPU, LP, BUP) can be changed on the fly. To ensure + * correct operation, frequencies must be selected so that BUPDIV ≥ LPDIV ≥ HSDIV. + * Also, frequencies must never exceed the specified maximum frequency for each clock domain. + * A module may be connected to several clock domains (for instance, AHB and APB). + * + * The general main clock tree for the CPU and associated buses is shown in + * \ref asfdoc_sam0_system_clock_module_clock_tree "the figure below". + * + * \anchor asfdoc_sam0_system_clock_module_clock_tree + * \dot + * digraph overview { + * rankdir=LR; + * clk_src [label="Clock Sources", shape=none, height=0]; + * node [label="CPU Bus" shape=ellipse] cpu_bus; + * node [label="AHB Bus" shape=ellipse] ahb_bus; + * node [label="APBx Bus" shape=ellipse] apb_bus; + * node [label="Main Bus\nPrescaler" shape=square] main_prescaler; + * node [label="CPU Clock\nPrescaler" shape=square] cpu_prescaler; + * node [label="Low Power Clock\nPrescaler" shape=square] low_power_prescaler; + * node [label="Backup clock\nPrescaler" shape=square] backup_prescaler; + * node [label="", shape=polygon, sides=4, distortion=0.6, orientation=90, style=filled, fillcolor=black, height=0.9, width=0.2] main_clock_mux; + * + * clk_src -> main_clock_mux; + * main_clock_mux -> main_prescaler; + * main_prescaler -> cpu_prescaler; + * main_prescaler -> low_power_prescaler; + * main_prescaler -> backup_prescaler; + * cpu_prescaler -> cpu_bus; + * cpu_prescaler -> ahb_bus; + * cpu_prescaler -> apb_bus; + * low_power_prescaler -> ahb_bus; + * low_power_prescaler -> apb_bus; + * backup_prescaler -> apb_bus; + * } + * \enddot + * + * \subsection asfdoc_sam0_system_clock_module_overview_clock_masking Clock Masking + * To save power, the input clock to one or more peripherals on the AHB and APBx + * buses can be masked away. When masked, no clock is passed into the module. + * Disabling of clocks of unused modules will prevent all access to the masked + * module, but will reduce the overall device power consumption. + * + * \subsection asfdoc_sam0_system_clock_module_overview_gclk Generic Clocks + * Within the SAM devices are a number of Generic Clocks; these are used to + * provide clocks to the various peripheral clock domains in the device in a + * standardized manner. One or more master source clocks can be selected as the + * input clock to a Generic Clock Generator, which can prescale down the input + * frequency to a slower rate for use in a peripheral. + * + * Additionally, a number of individually selectable Generic Clock Channels are + * provided, which multiplex and gate the various generator outputs for one or + * more peripherals within the device. This setup allows for a single common + * generator to feed one or more channels, which can then be enabled or disabled + * individually as required. + * + * \anchor asfdoc_sam0_system_clock_module_chain_overview + * \dot + * digraph overview { + * rankdir=LR; + * node [label="Clock\nSource a" shape=square] system_clock_source; + * node [label="Generator n" shape=square] clock_gen; + * node [label="Channel x" shape=square] clock_chan0; + * node [label="Channel y" shape=square] clock_chan1; + * node [label="Peripheral x" shape=ellipse style=filled fillcolor=lightgray] peripheral0; + * node [label="Peripheral y" shape=ellipse style=filled fillcolor=lightgray] peripheral1; + * + * system_clock_source -> clock_gen; + * clock_gen -> clock_chan0; + * clock_chan0 -> peripheral0; + * clock_gen -> clock_chan1; + * clock_chan1 -> peripheral1; + * } + * \enddot + * + * \subsubsection asfdoc_sam0_system_clock_module_chain_example Clock Chain Example + * An example setup of a complete clock chain within the device is shown in + * \ref asfdoc_sam0_system_clock_module_chain_example_fig "the figure below". + * + * \anchor asfdoc_sam0_system_clock_module_chain_example_fig + * \dot + * digraph overview { + * rankdir=LR; + * node [label="External\nOscillator" shape=square] system_clock_source0; + * node [label="Generator 0" shape=square] clock_gen0; + * node [label="Channel x" shape=square] clock_chan0; + * node [label="Core CPU" shape=ellipse style=filled fillcolor=lightgray] peripheral0; + * + * system_clock_source0 -> clock_gen0; + * clock_gen0 -> clock_chan0; + * clock_chan0 -> peripheral0; + * node [label="16MHz R/C\nOscillator (OSC16M)" shape=square fillcolor=white] system_clock_source1; + * node [label="Generator 1" shape=square] clock_gen1; + * node [label="Channel y" shape=square] clock_chan1; + * node [label="Channel z" shape=square] clock_chan2; + * node [label="SERCOM\nModule" shape=ellipse style=filled fillcolor=lightgray] peripheral1; + * node [label="Timer\nModule" shape=ellipse style=filled fillcolor=lightgray] peripheral2; + * + * system_clock_source1 -> clock_gen1; + * clock_gen1 -> clock_chan1; + * clock_gen1 -> clock_chan2; + * clock_chan1 -> peripheral1; + * clock_chan2 -> peripheral2; + * } + * \enddot + * + * \subsubsection asfdoc_sam0_system_clock_module_overview_gclk_generators Generic Clock Generators + * Each Generic Clock generator within the device can source its input clock + * from one of the provided Source Clocks, and prescale the output for one or + * more Generic Clock Channels in a one-to-many relationship. The generators + * thus allow for several clocks to be generated of different frequencies, + * power usages, and accuracies, which can be turned on and off individually to + * disable the clocks to multiple peripherals as a group. + * + * \subsubsection asfdoc_sam0_system_clock_module_overview_gclk_channels Generic Clock Channels + * To connect a Generic Clock Generator to a peripheral within the + * device, a Generic Clock Channel is used. Each peripheral or + * peripheral group has an associated Generic Clock Channel, which serves as the + * clock input for the peripheral(s). To supply a clock to the peripheral + * module(s), the associated channel must be connected to a running Generic + * Clock Generator and the channel enabled. + * + * \section asfdoc_sam0_system_clock_special_considerations Special Considerations + * + * There are no special considerations for this module. + * + * + * \section asfdoc_sam0_system_clock_extra_info Extra Information + * + * For extra information, see \ref asfdoc_sam0_system_clock_extra. This includes: + * - \ref asfdoc_sam0_system_clock_extra_acronyms + * - \ref asfdoc_sam0_system_clock_extra_dependencies + * - \ref asfdoc_sam0_system_clock_extra_errata + * - \ref asfdoc_sam0_system_clock_extra_history + * + * + * \section asfdoc_sam0_system_clock_examples Examples + * + * For a list of examples related to this driver, see + * \ref asfdoc_sam0_system_clock_exqsg. + * + * + * \section asfdoc_sam0_system_clock_api_overview API Overview + * @{ + */ + +#include +#include + + + +/** + * \brief Available start-up times for the XOSC32K. + * + * Available external 32KHz oscillator start-up times, as a number of external + * clock cycles. + */ +enum system_xosc32k_startup { + /** Wait 2048 clock cycles until the clock source is considered stable */ + SYSTEM_XOSC32K_STARTUP_2048, + /** Wait 4096 clock cycles until the clock source is considered stable */ + SYSTEM_XOSC32K_STARTUP_4096, + /** Wait 16384 clock cycles until the clock source is considered stable */ + SYSTEM_XOSC32K_STARTUP_16384, + /** Wait 32768 clock cycles until the clock source is considered stable */ + SYSTEM_XOSC32K_STARTUP_32768, + /** Wait 65536 clock cycles until the clock source is considered stable */ + SYSTEM_XOSC32K_STARTUP_65536, + /** Wait 131072 clock cycles until the clock source is considered stable */ + SYSTEM_XOSC32K_STARTUP_131072, + /** Wait 262144 clock cycles until the clock source is considered stable */ + SYSTEM_XOSC32K_STARTUP_262144, +}; + +/** + * \brief Available start-up times for the XOSC. + * + * Available external oscillator start-up times, as a number of external clock + * cycles. + */ +enum system_xosc_startup { + /** Wait one clock cycle until the clock source is considered stable */ + SYSTEM_XOSC_STARTUP_1, + /** Wait two clock cycles until the clock source is considered stable */ + SYSTEM_XOSC_STARTUP_2, + /** Wait four clock cycles until the clock source is considered stable */ + SYSTEM_XOSC_STARTUP_4, + /** Wait eight clock cycles until the clock source is considered stable */ + SYSTEM_XOSC_STARTUP_8, + /** Wait 16 clock cycles until the clock source is considered stable */ + SYSTEM_XOSC_STARTUP_16, + /** Wait 32 clock cycles until the clock source is considered stable */ + SYSTEM_XOSC_STARTUP_32, + /** Wait 64 clock cycles until the clock source is considered stable */ + SYSTEM_XOSC_STARTUP_64, + /** Wait 128 clock cycles until the clock source is considered stable */ + SYSTEM_XOSC_STARTUP_128, + /** Wait 256 clock cycles until the clock source is considered stable */ + SYSTEM_XOSC_STARTUP_256, + /** Wait 512 clock cycles until the clock source is considered stable */ + SYSTEM_XOSC_STARTUP_512, + /** Wait 1024 clock cycles until the clock source is considered stable */ + SYSTEM_XOSC_STARTUP_1024, + /** Wait 2048 clock cycles until the clock source is considered stable */ + SYSTEM_XOSC_STARTUP_2048, + /** Wait 4096 clock cycles until the clock source is considered stable */ + SYSTEM_XOSC_STARTUP_4096, + /** Wait 8192 clock cycles until the clock source is considered stable */ + SYSTEM_XOSC_STARTUP_8192, + /** Wait 16384 clock cycles until the clock source is considered stable */ + SYSTEM_XOSC_STARTUP_16384, + /** Wait 32768 clock cycles until the clock source is considered stable */ + SYSTEM_XOSC_STARTUP_32768, +}; + +/** + * \brief Available start-up times for the OSC32K. + * + * Available internal 32KHz oscillator start-up times, as a number of internal + * OSC32K clock cycles. + */ +enum system_osc32k_startup { + /** Wait three clock cycles until the clock source is considered stable */ + SYSTEM_OSC32K_STARTUP_3, + /** Wait four clock cycles until the clock source is considered stable */ + SYSTEM_OSC32K_STARTUP_4, + /** Wait six clock cycles until the clock source is considered stable */ + SYSTEM_OSC32K_STARTUP_6, + /** Wait ten clock cycles until the clock source is considered stable */ + SYSTEM_OSC32K_STARTUP_10, + /** Wait 18 clock cycles until the clock source is considered stable */ + SYSTEM_OSC32K_STARTUP_18, + /** Wait 34 clock cycles until the clock source is considered stable */ + SYSTEM_OSC32K_STARTUP_34, + /** Wait 66 clock cycles until the clock source is considered stable */ + SYSTEM_OSC32K_STARTUP_66, + /** Wait 130 clock cycles until the clock source is considered stable */ + SYSTEM_OSC32K_STARTUP_130, +}; + +/** + * \brief Frequency selection for the internal 16MHz system clock. + * + * Available frequency selection for the internal 16MHz (nominal) system clock. + */ +enum system_osc16m_fsel { + /** Frequency Selection 4MHz */ + SYSTEM_OSC16M_4M, + /** Frequency Selection 8MHz */ + SYSTEM_OSC16M_8M, + /** Frequency Selection 12MHz */ + SYSTEM_OSC16M_12M, + /** Frequency Selection 16MHz */ + SYSTEM_OSC16M_16M, +}; + + + +/** + * \brief Main CPU, Lowpower and Backup clock division. + * + * Available division ratios for the CPU and Lowpower and Backup clocks. + */ +enum system_main_clock_div { + /** Divide Main clock by one */ + SYSTEM_MAIN_CLOCK_DIV_1, + /** Divide Main clock by two */ + SYSTEM_MAIN_CLOCK_DIV_2, + /** Divide Main clock by four */ + SYSTEM_MAIN_CLOCK_DIV_4, + /** Divide Main clock by eight */ + SYSTEM_MAIN_CLOCK_DIV_8, + /** Divide Main clock by 16 */ + SYSTEM_MAIN_CLOCK_DIV_16, + /** Divide Main clock by 32 */ + SYSTEM_MAIN_CLOCK_DIV_32, + /** Divide Main clock by 64 */ + SYSTEM_MAIN_CLOCK_DIV_64, + /** Divide Main clock by 128 */ + SYSTEM_MAIN_CLOCK_DIV_128, +}; + +/** + * \brief External clock source types. + * + * Available external clock source types. + */ +enum system_clock_external { + /** The external clock source is a crystal oscillator */ + SYSTEM_CLOCK_EXTERNAL_CRYSTAL, + /** The connected clock source is an external logic level clock signal */ + SYSTEM_CLOCK_EXTERNAL_CLOCK, +}; + +/** + * \brief Operating modes of the DFLL clock source. + * + * Available operating modes of the DFLL clock source module. + */ +enum system_clock_dfll_loop_mode { + /** The DFLL is operating in open loop mode with no feedback */ + SYSTEM_CLOCK_DFLL_LOOP_MODE_OPEN, + /** The DFLL is operating in closed loop mode with frequency feedback from + * a low frequency reference clock + */ + SYSTEM_CLOCK_DFLL_LOOP_MODE_CLOSED = OSCCTRL_DFLLCTRL_MODE, + +#ifdef OSCCTRL_DFLLCTRL_USBCRM + /** The DFLL is operating in USB recovery mode with frequency feedback + * from USB SOF + */ + SYSTEM_CLOCK_DFLL_LOOP_MODE_USB_RECOVERY = OSCCTRL_DFLLCTRL_USBCRM, +#endif +}; + +/** + * \brief Locking behavior for the DFLL during device wake-up. + * + * DFLL lock behavior modes on device wake-up from sleep. + */ +enum system_clock_dfll_wakeup_lock { + /** Keep DFLL lock when the device wakes from sleep */ + SYSTEM_CLOCK_DFLL_WAKEUP_LOCK_KEEP, + /** Lose DFLL lock when the devices wakes from sleep */ + SYSTEM_CLOCK_DFLL_WAKEUP_LOCK_LOSE = OSCCTRL_DFLLCTRL_LLAW, +}; + +/** + * \brief Fine tracking behavior for the DFLL once a lock has been acquired. + * + * DFLL fine tracking behavior modes after a lock has been acquired. + */ +enum system_clock_dfll_stable_tracking { + /** Keep tracking after the DFLL has gotten a fine lock */ + SYSTEM_CLOCK_DFLL_STABLE_TRACKING_TRACK_AFTER_LOCK, + /** Stop tracking after the DFLL has gotten a fine lock */ + SYSTEM_CLOCK_DFLL_STABLE_TRACKING_FIX_AFTER_LOCK = OSCCTRL_DFLLCTRL_STABLE, +}; + +/** + * \brief Chill cycle behavior of the DFLL module. + * + * DFLL chill cycle behavior modes of the DFLL module. A chill cycle is a period + * of time when the DFLL output frequency is not measured by the unit, to allow + * the output to stabilize after a change in the input clock source. + */ +enum system_clock_dfll_chill_cycle { + /** Enable a chill cycle, where the DFLL output frequency is not measured */ + SYSTEM_CLOCK_DFLL_CHILL_CYCLE_ENABLE, + /** Disable a chill cycle, where the DFLL output frequency is not measured */ + SYSTEM_CLOCK_DFLL_CHILL_CYCLE_DISABLE = OSCCTRL_DFLLCTRL_CCDIS, +}; + +/** + * \brief QuickLock settings for the DFLL module. + * + * DFLL QuickLock settings for the DFLL module, to allow for a faster lock of + * the DFLL output frequency at the expense of accuracy. + */ +enum system_clock_dfll_quick_lock { + /** Enable the QuickLock feature for looser lock requirements on the DFLL */ + SYSTEM_CLOCK_DFLL_QUICK_LOCK_ENABLE, + /** Disable the QuickLock feature for strict lock requirements on the DFLL */ + SYSTEM_CLOCK_DFLL_QUICK_LOCK_DISABLE = OSCCTRL_DFLLCTRL_QLDIS, +}; + +/** + * \brief Available clock sources in the system. + * + * Clock sources available to the GCLK generators. + */ +enum system_clock_source { + /** Internal 16MHz RC oscillator */ + SYSTEM_CLOCK_SOURCE_OSC16M = GCLK_SOURCE_OSC16M, + /** Internal 32KHz RC oscillator */ + SYSTEM_CLOCK_SOURCE_OSC32K = GCLK_SOURCE_OSC32K, + /** External oscillator */ + SYSTEM_CLOCK_SOURCE_XOSC = GCLK_SOURCE_XOSC , + /** External 32KHz oscillator */ + SYSTEM_CLOCK_SOURCE_XOSC32K = GCLK_SOURCE_XOSC32K, + /** Digital Frequency Locked Loop (DFLL) */ + SYSTEM_CLOCK_SOURCE_DFLL = GCLK_SOURCE_DFLL48M, + /** Internal Ultra Low Power 32KHz oscillator */ + SYSTEM_CLOCK_SOURCE_ULP32K = GCLK_SOURCE_OSCULP32K, + /** Generator input pad */ + SYSTEM_CLOCK_SOURCE_GCLKIN = GCLK_SOURCE_GCLKIN, + /** Generic clock generator one output */ + SYSTEM_CLOCK_SOURCE_GCLKGEN1 = GCLK_SOURCE_GCLKGEN1, + +#if SAMR34JXXA + /** Digital Phase Locked Loop (DPLL) */ + SYSTEM_CLOCK_SOURCE_DPLL = GCLK_SOURCE_FDPLL, +#else + SYSTEM_CLOCK_SOURCE_DPLL = GCLK_SOURCE_DPLL96M, +#endif + +}; + +/** + * \brief List of APB peripheral buses. + * + * Available bus clock domains on the APB bus. + */ +enum system_clock_apb_bus { + /** Peripheral bus A on the APB bus */ + SYSTEM_CLOCK_APB_APBA, + /** Peripheral bus B on the APB bus */ + SYSTEM_CLOCK_APB_APBB, + /** Peripheral bus C on the APB bus */ + SYSTEM_CLOCK_APB_APBC, + /** Peripheral bus D on the APB bus */ + SYSTEM_CLOCK_APB_APBD, + /** Peripheral bus E on the APB bus */ + SYSTEM_CLOCK_APB_APBE, +}; + +/** + * \brief Configuration structure for XOSC. + * + * External oscillator clock configuration structure. + */ +struct system_clock_source_xosc_config { + /** External clock type */ + enum system_clock_external external_clock; + /** Crystal oscillator start-up time */ + enum system_xosc_startup startup_time; + /** Enable automatic amplitude gain control */ + bool auto_gain_control; + /** External clock/crystal frequency */ + uint32_t frequency; + /** Keep the XOSC enabled in standby sleep mode */ + bool run_in_standby; + /** Run On Demand. If this is set the XOSC won't run + * until requested by a peripheral */ + bool on_demand; +}; + +/** + * \brief Configuration structure for XOSC32K. + * + * External 32KHz oscillator clock configuration structure. + */ +struct system_clock_source_xosc32k_config { + /** External clock type */ + enum system_clock_external external_clock; + /** Crystal oscillator start-up time */ + enum system_xosc32k_startup startup_time; + /** Enable 1KHz output */ + bool enable_1khz_output; + /** Enable 32KHz output */ + bool enable_32khz_output; + /** External clock/crystal frequency */ + uint32_t frequency; + /** Keep the XOSC32K enabled in standby sleep mode */ + bool run_in_standby; + /** Run On Demand. If this is set the XOSC32K won't run + * until requested by a peripheral */ + bool on_demand; + /** Lock configuration after it has been written, + * a device reset will release the lock */ + bool write_once; +}; + +/** + * \brief Configuration structure for OSC16M. + * + * Internal 16MHz (nominal) oscillator configuration structure. + */ +struct system_clock_source_osc16m_config { + /** Internal 16MHz RC oscillator prescaler */ + enum system_osc16m_fsel fsel; + /** Keep the OSC16M enabled in standby sleep mode */ + bool run_in_standby; + /** Run On Demand. If this is set the OSC16M won't run + * until requested by a peripheral */ + bool on_demand; +}; + +/** + * \brief Configuration structure for OSCULP32K. + * + * Internal 32KHz Ultra Low Power oscillator configuration structure. + */ +struct system_clock_source_osculp32k_config { + /** Lock configuration after it has been written, + * a device reset will release the lock */ + bool write_once; +}; + +/** + * \brief Configuration structure for OSCULP32K. + * + * Internal 32KHz oscillator configuration structure. + */ +struct system_clock_source_osc32k_config { + /** Start-up time */ + enum system_osc32k_startup startup_time; + /** Enable 1KHz output */ + bool enable_1khz_output; + /** Enable 32KHz output */ + bool enable_32khz_output; + /** Keep the OSC32K enabled in standby sleep mode */ + bool run_in_standby; + /** Run On Demand. If this is set the OSC32K won't run + * until requested by a peripheral */ + bool on_demand; + /** Lock configuration after it has been written, + * a device reset will release the lock */ + bool write_once; +}; + +/** + * \brief Configuration structure for DFLL. + * + * DFLL oscillator configuration structure. + */ +struct system_clock_source_dfll_config { + /** Loop mode */ + enum system_clock_dfll_loop_mode loop_mode; + /** Run On Demand. If this is set the DFLL won't run + * until requested by a peripheral */ + bool on_demand; + /** Run in stanby*/ + bool run_in_stanby; + /** Enable quick lock */ + enum system_clock_dfll_quick_lock quick_lock; + /** Enable chill cycle */ + enum system_clock_dfll_chill_cycle chill_cycle; + /** DFLL lock state on wakeup */ + enum system_clock_dfll_wakeup_lock wakeup_lock; + /** DFLL tracking after fine lock */ + enum system_clock_dfll_stable_tracking stable_tracking; + /** Coarse calibration value (Open loop mode) */ + uint8_t coarse_value; + /** Fine calibration value (Open loop mode) */ + uint16_t fine_value; + /** Coarse adjustment maximum step size (Closed loop mode) */ + uint8_t coarse_max_step; + /** Fine adjustment maximum step size (Closed loop mode) */ + uint16_t fine_max_step; + /** DFLL multiply factor (Closed loop mode) */ + uint16_t multiply_factor; +}; + +/** + * \name External Oscillator Management + * @{ + */ + +/** + * \brief Retrieve the default configuration for XOSC. + * + * Fills a configuration structure with the default configuration for an + * external oscillator module: + * - External Crystal + * - Start-up time of 16384 external clock cycles + * - Automatic crystal gain control mode enabled + * - Frequency of 12MHz + * - Don't run in STANDBY sleep mode + * - Run only when requested by peripheral (on demand) + * + * \param[out] config Configuration structure to fill with default values + */ +static inline void system_clock_source_xosc_get_config_defaults( + struct system_clock_source_xosc_config *const config) +{ + Assert(config); + + config->external_clock = SYSTEM_CLOCK_EXTERNAL_CRYSTAL; + config->startup_time = SYSTEM_XOSC_STARTUP_16384; + config->auto_gain_control = true; + config->frequency = 12000000UL; + config->run_in_standby = false; + config->on_demand = true; +} + +void system_clock_source_xosc_set_config( + struct system_clock_source_xosc_config *const config); + +/** + * @} + */ + + +/** + * \name External 32KHz Oscillator Management + * @{ + */ + +/** + * \brief Retrieve the default configuration for XOSC32K. + * + * Fills a configuration structure with the default configuration for an + * external 32KHz oscillator module: + * - External Crystal + * - Start-up time of 16384 external clock cycles + * - Automatic crystal gain control mode disabled + * - Frequency of 32.768KHz + * - 1KHz clock output disabled + * - 32KHz clock output enabled + * - Don't run in STANDBY sleep mode + * - Run only when requested by peripheral (on demand) + * - Don't lock registers after configuration has been written + * + * \param[out] config Configuration structure to fill with default values + */ +static inline void system_clock_source_xosc32k_get_config_defaults( + struct system_clock_source_xosc32k_config *const config) +{ + Assert(config); + + config->external_clock = SYSTEM_CLOCK_EXTERNAL_CRYSTAL; + config->startup_time = SYSTEM_XOSC32K_STARTUP_16384; + config->frequency = 32768UL; + config->enable_1khz_output = false; + config->enable_32khz_output = true; + config->run_in_standby = false; + config->on_demand = true; + config->write_once = false; +} + +void system_clock_source_xosc32k_set_config( + struct system_clock_source_xosc32k_config *const config); +/** + * @} + */ + + +/** + * \name Internal 32KHz Oscillator Management + * @{ + */ + +/** + * \brief Retrieve the default configuration for OSC32K. + * + * Fills a configuration structure with the default configuration for an + * internal 32KHz oscillator module: + * - 1KHz clock output enabled + * - 32KHz clock output enabled + * - Don't run in STANDBY sleep mode + * - Run only when requested by peripheral (on demand) + * - Set start-up time to 130 cycles + * - Don't lock registers after configuration has been written + * + * \param[out] config Configuration structure to fill with default values + */ +static inline void system_clock_source_osc32k_get_config_defaults( + struct system_clock_source_osc32k_config *const config) +{ + Assert(config); + + config->enable_1khz_output = true; + config->enable_32khz_output = true; + config->run_in_standby = false; + config->on_demand = true; + config->startup_time = SYSTEM_OSC32K_STARTUP_130; + config->write_once = false; +} + +void system_clock_source_osc32k_set_config( + struct system_clock_source_osc32k_config *const config); + +/** + * @} + */ + +/** + * \name Internal Ultra Low Power 32KHz Oscillator Management + * @{ + */ + +/** + * \brief Retrieve the default configuration for OSCULP32K. + * + * Fills a configuration structure with the default configuration for an + * internal Ultra Low Power 32KHz oscillator module: + * - 1KHz clock output enabled + * - 32KHz clock output enabled + * + * \param[out] config Configuration structure to fill with default values + */ +static inline void system_clock_source_osculp32k_get_config_defaults( + struct system_clock_source_osculp32k_config *const config) +{ + Assert(config); + + config->write_once = false; +} + +void system_clock_source_osculp32k_set_config( + struct system_clock_source_osculp32k_config *const config); + +/** + * @} + */ + + +/** + * \name Internal 16MHz Oscillator Management + * @{ + */ + +/** + * \brief Retrieve the default configuration for OSC16M. + * + * Fills a configuration structure with the default configuration for an + * internal 16MHz (nominal) oscillator module: + * - Clock output frequency select 4MHz + * - Don't run in STANDBY sleep mode + * - Run only when requested by peripheral (on demand) + * + * \param[out] config Configuration structure to fill with default values + */ +static inline void system_clock_source_osc16m_get_config_defaults( + struct system_clock_source_osc16m_config *const config) +{ + Assert(config); + + config->fsel = SYSTEM_OSC16M_4M; + config->run_in_standby = false; + config->on_demand = true; +} + +void system_clock_source_osc16m_set_config( + struct system_clock_source_osc16m_config *const config); + +/** + * @} + */ + + +/** + * \name Internal DFLL Management + * @{ + */ + +/** + * \brief Retrieve the default configuration for DFLL. + * + * Fills a configuration structure with the default configuration for a + * DFLL oscillator module: + * - Open loop mode + * - QuickLock mode enabled + * - Chill cycle enabled + * - Output frequency lock maintained during device wake-up + * - Continuous tracking of the output frequency + * - Default tracking values at the mid-points for both coarse and fine + * tracking parameters + * - Don't run in STANDBY sleep mode + * - Run only when requested by peripheral (on demand) + * + * \param[out] config Configuration structure to fill with default values + */ +static inline void system_clock_source_dfll_get_config_defaults( + struct system_clock_source_dfll_config *const config) +{ + Assert(config); + + config->loop_mode = SYSTEM_CLOCK_DFLL_LOOP_MODE_OPEN; + config->quick_lock = SYSTEM_CLOCK_DFLL_QUICK_LOCK_ENABLE; + config->chill_cycle = SYSTEM_CLOCK_DFLL_CHILL_CYCLE_ENABLE; + config->wakeup_lock = SYSTEM_CLOCK_DFLL_WAKEUP_LOCK_KEEP; + config->stable_tracking = SYSTEM_CLOCK_DFLL_STABLE_TRACKING_TRACK_AFTER_LOCK; + config->on_demand = true; + config->run_in_stanby = false; + + /* Open loop mode calibration value */ + config->coarse_value = 0x1f / 4; /* Midpoint */ + config->fine_value = 0xff / 4; /* Midpoint */ + + /* Closed loop mode */ + config->coarse_max_step = 1; + config->fine_max_step = 1; + config->multiply_factor = 12; /* Multiply 4MHz by 12 to get 48MHz */ +} + +void system_clock_source_dfll_set_config( + struct system_clock_source_dfll_config *const config); + +/** + * @} + */ + +/** + * \name Clock Source Management + * @{ + */ +enum status_code system_clock_source_write_calibration( + const enum system_clock_source system_clock_source, + const uint16_t calibration_value, + const uint8_t freq_range); + +enum status_code system_clock_source_enable( + const enum system_clock_source system_clock_source); + +enum status_code system_clock_source_disable( + const enum system_clock_source clk_source); + +bool system_clock_source_is_ready( + const enum system_clock_source clk_source); + +uint32_t system_clock_source_get_hz( + const enum system_clock_source clk_source); + +/** + * @} + */ + +/** + * \name Main Clock Management + * @{ + */ + +/** + * \brief Enable or disable the main clock failure detection. + * + * This mechanism allows switching automatically the main clock to the safe + * RCSYS clock, when the main clock source is considered off. + * + * This may happen for instance when an external crystal is selected as the + * clock source of the main clock and the crystal dies. The mechanism is to + * detect, during a RCSYS period, at least one rising edge of the main clock. + * If no rising edge is seen the clock is considered failed. + * As soon as the detector is enabled, the clock failure detector + * (CFD) will monitor the divided main clock. When a clock failure is detected, + * the main clock automatically switches to the RCSYS clock and the CFD + * interrupt is generated if enabled. + * + * \note The failure detect must be disabled if the system clock is the same or + * slower than 32KHz as it will believe the system clock has failed with + * a too slow clock. + * + * \param[in] enable Boolean \c true to enable, \c false to disable detection + */ +static inline void system_main_clock_set_failure_detect( + const bool enable) +{ +#ifdef MCLK_CTRLA_CFDEN + if (enable) { + MCLK->CTRLA.reg |= MCLK_CTRLA_CFDEN; + } else { + MCLK->CTRLA.reg &= ~MCLK_CTRLA_CFDEN; + } +#endif +} + +/** + * \brief Set main CPU clock divider. + * + * Sets the clock divider used on the main clock to provide the CPU clock. + * + * \param[in] divider CPU clock divider + */ +static inline void system_cpu_clock_set_divider( + const enum system_main_clock_div divider) +{ + MCLK->CPUDIV.reg = MCLK_CPUDIV_CPUDIV(1 << divider); +} + +/** + * \brief Set Low-Power Clock divider. + * + * Sets the clock divider used on the main clock to provide the CPU clock. + * + * \param[in] divider CPU clock divider to set + */ +static inline void system_low_power_clock_set_divider( + const enum system_main_clock_div divider) +{ + MCLK->LPDIV.reg = MCLK_LPDIV_LPDIV(1 << divider); +} + +/** + * \brief Set Backup Clock divider. + * + * Sets the clock divider used on the main clock to provide the CPU clock. + * + * \param[in] divider CPU clock divider + */ +static inline void system_backup_clock_set_divider( + const enum system_main_clock_div divider) +{ + MCLK->BUPDIV.reg = MCLK_BUPDIV_BUPDIV(1 << divider); +} + + +/** + * \brief Retrieves the current frequency of the CPU core. + * + * Retrieves the operating frequency of the CPU core, obtained from the main + * generic clock and the set CPU bus divider. + * + * \return Current CPU frequency in Hz. + */ +static inline uint32_t system_cpu_clock_get_hz(void) +{ + return (system_gclk_gen_get_hz(GCLK_GENERATOR_0) / MCLK->CPUDIV.reg); + +} + +/** + * \brief Retrieves the current frequency of Low-Power clock. + * + * Retrieves the operating frequency of Low-Power, obtained from Low-Power + * clock and the set Low-Power clock divider. + * + * \return Current CPU frequency in Hz. + */ +static inline uint32_t system_low_power_clock_get_hz(void) +{ + return (system_gclk_gen_get_hz(GCLK_GENERATOR_0) >> (MCLK->LPDIV.reg - 1)); + +} + +/** + * \brief Retrieves the current frequency of backup clock. + * + * Retrieves the operating frequency of backup clock, obtained from backup + * clock and the set backup clock divider. + * + * \return Current CPU frequency in Hz. + */ +static inline uint32_t system_backup_clock_get_hz(void) +{ + return (system_gclk_gen_get_hz(GCLK_GENERATOR_0) >> (MCLK->BUPDIV.reg - 1)); + +} + + +/** + * @} + */ + +/** + * \name Bus Clock Masking + * @{ + */ + +/** + * \brief Set bits in the clock mask for the AHB bus. + * + * This function will set bits in the clock mask for the AHB bus. + * Any bits set to 1 will enable that clock, 0 bits in the mask + * will be ignored + * + * \param[in] ahb_mask AHB clock mask + */ +static inline void system_ahb_clock_set_mask( + const uint32_t ahb_mask) +{ + MCLK->AHBMASK.reg |= ahb_mask; +} + +/** + * \brief Clear bits in the clock mask for the AHB bus. + * + * This function will clear bits in the clock mask for the AHB bus. + * Any bits set to 1 will disable that clock, zero bits in the mask + * will be ignored. + * + * \param[in] ahb_mask AHB clock mask + */ +static inline void system_ahb_clock_clear_mask( + const uint32_t ahb_mask) +{ + MCLK->AHBMASK.reg &= ~ahb_mask; +} + +/** + * \brief Set bits in the clock mask for an APBx bus. + * + * This function will set bits in the clock mask for an APBx bus. + * Any bits set to 1 will enable the corresponding module clock, zero bits in + * the mask will be ignored. + * + * \param[in] mask APBx clock mask, a \c SYSTEM_CLOCK_APB_APBx constant from + * the device header files + * \param[in] bus Bus to set clock mask bits for, a mask of \c PM_APBxMASK_* + * constants from the device header files + * + * \returns Status indicating the result of the clock mask change operation. + * + * \retval STATUS_ERR_INVALID_ARG Invalid bus given + * \retval STATUS_OK The clock mask was set successfully + */ +static inline enum status_code system_apb_clock_set_mask( + const enum system_clock_apb_bus bus, + const uint32_t mask) +{ + switch (bus) { + case SYSTEM_CLOCK_APB_APBA: + MCLK->APBAMASK.reg |= mask; + break; + + case SYSTEM_CLOCK_APB_APBB: + MCLK->APBBMASK.reg |= mask; + break; + + case SYSTEM_CLOCK_APB_APBC: + MCLK->APBCMASK.reg |= mask; + break; + case SYSTEM_CLOCK_APB_APBD: + MCLK->APBDMASK.reg |= mask; + break; + case SYSTEM_CLOCK_APB_APBE: + MCLK->APBEMASK.reg |= mask; + break; + default: + Assert(false); + return STATUS_ERR_INVALID_ARG; + + } + + return STATUS_OK; +} + +/** + * \brief Clear bits in the clock mask for an APBx bus. + * + * This function will clear bits in the clock mask for an APBx bus. + * Any bits set to 1 will disable the corresponding module clock, zero bits in + * the mask will be ignored. + * + * \param[in] mask APBx clock mask, a \c SYSTEM_CLOCK_APB_APBx constant from + * the device header files + * \param[in] bus Bus to clear clock mask bits + * + * \returns Status indicating the result of the clock mask change operation. + * + * \retval STATUS_ERR_INVALID_ARG Invalid bus ID was given + * \retval STATUS_OK The clock mask was changed successfully + */ +static inline enum status_code system_apb_clock_clear_mask( + const enum system_clock_apb_bus bus, + const uint32_t mask) +{ + switch (bus) { + case SYSTEM_CLOCK_APB_APBA: + MCLK->APBAMASK.reg &= ~mask; + break; + + case SYSTEM_CLOCK_APB_APBB: + MCLK->APBBMASK.reg &= ~mask; + break; + + case SYSTEM_CLOCK_APB_APBC: + MCLK->APBCMASK.reg &= ~mask; + break; + case SYSTEM_CLOCK_APB_APBD: + MCLK->APBDMASK.reg &= ~mask; + break; + case SYSTEM_CLOCK_APB_APBE: + MCLK->APBEMASK.reg &= ~mask; + break; + default: + Assert(false); + return STATUS_ERR_INVALID_ARG; + } + + return STATUS_OK; +} + +/** + * @} + */ + +/** + * \brief Reference clock source of the DPLL module. + */ +enum system_clock_source_dpll_reference_clock { + /** Select XOSC32K as clock reference */ + SYSTEM_CLOCK_SOURCE_DPLL_REFERENCE_CLOCK_XOSC32K, + /** Select XOSC as clock reference */ + SYSTEM_CLOCK_SOURCE_DPLL_REFERENCE_CLOCK_XOSC, + /** Select GCLK as clock reference */ + SYSTEM_CLOCK_SOURCE_DPLL_REFERENCE_CLOCK_GCLK, +}; + +/** + * \brief Lock time-out value of the DPLL module. + */ +enum system_clock_source_dpll_lock_time { + /** Set no time-out as default */ + SYSTEM_CLOCK_SOURCE_DPLL_LOCK_TIME_DEFAULT, + /** Set time-out if no lock within 8ms */ + SYSTEM_CLOCK_SOURCE_DPLL_LOCK_TIME_8MS = 0x04, + /** Set time-out if no lock within 9ms */ + SYSTEM_CLOCK_SOURCE_DPLL_LOCK_TIME_9MS, + /** Set time-out if no lock within 10ms */ + SYSTEM_CLOCK_SOURCE_DPLL_LOCK_TIME_10MS, + /** Set time-out if no lock within 11ms */ + SYSTEM_CLOCK_SOURCE_DPLL_LOCK_TIME_11MS, +}; + +/** + * \brief Filter type of the DPLL module. + */ +enum system_clock_source_dpll_filter { + /** Default filter mode */ + SYSTEM_CLOCK_SOURCE_DPLL_FILTER_DEFAULT, + /** Low bandwidth filter */ + SYSTEM_CLOCK_SOURCE_DPLL_FILTER_LOW_BANDWIDTH_FILTER, + /** High bandwidth filter */ + SYSTEM_CLOCK_SOURCE_DPLL_FILTER_HIGH_BANDWIDTH_FILTER, + /** High damping filter */ + SYSTEM_CLOCK_SOURCE_DPLL_FILTER_HIGH_DAMPING_FILTER, +}; + +/** + * \brief DPLL Output Clock Prescaler. + */ +enum system_clock_source_dpll_prescaler { + /** DPLL output is divided by 1 */ + SYSTEM_CLOCK_SOURCE_DPLL_DIV_1, + /** DPLL output is divided by 2 */ + SYSTEM_CLOCK_SOURCE_DPLL_DIV_2, + /** DPLL output is divided by 4 */ + SYSTEM_CLOCK_SOURCE_DPLL_DIV_4, +}; + +/** + * \brief Configuration structure for DPLL. + * + * DPLL oscillator configuration structure. + */ +struct system_clock_source_dpll_config { + /** Run On Demand. If this is set the DPLL won't run + * until requested by a peripheral */ + bool on_demand; + /** Keep the DPLL enabled in standby sleep mode */ + bool run_in_standby; + /** Bypass lock signal */ + bool lock_bypass; + /** Wake up fast. If this is set DPLL output clock is enabled after + * the start-up time */ + bool wake_up_fast; + /** Enable low power mode */ + bool low_power_enable; + + /** Output frequency of the clock */ + uint32_t output_frequency; + /** Reference frequency of the clock */ + uint32_t reference_frequency; + /** Devider of reference clock */ + uint16_t reference_divider; + + /** Filter type of the DPLL module */ + enum system_clock_source_dpll_filter filter; + /** Lock time-out value of the DPLL module */ + enum system_clock_source_dpll_lock_time lock_time; + /** Reference clock source of the DPLL module */ + enum system_clock_source_dpll_reference_clock reference_clock; + /** DPLL prescaler */ + enum system_clock_source_dpll_prescaler prescaler; +}; + +/** + * \name Internal DPLL Management + * @{ + */ + +/** + * \brief Retrieve the default configuration for DPLL. + * + * Fills a configuration structure with the default configuration for a + * DPLL oscillator module: + * - Run only when requested by peripheral (on demand) + * - Don't run in STANDBY sleep mode + * - Lock bypass disabled + * - Fast wake up disabled + * - Low power mode disabled + * - Output frequency is 48MHz + * - Reference clock frequency is 32768Hz + * - Not divide reference clock + * - Select REF0 as reference clock + * - Set lock time to default mode + * - Use default filter + * + * \param[out] config Configuration structure to fill with default values + */ +static inline void system_clock_source_dpll_get_config_defaults( + struct system_clock_source_dpll_config *const config) +{ + config->on_demand = true; + config->run_in_standby = false; + config->lock_bypass = false; + config->wake_up_fast = false; + config->low_power_enable = false; + + config->output_frequency = 48000000; + config->reference_frequency = 32768; + config->reference_divider = 1; + config->reference_clock = SYSTEM_CLOCK_SOURCE_DPLL_REFERENCE_CLOCK_GCLK; + config->prescaler = SYSTEM_CLOCK_SOURCE_DPLL_DIV_1; + + config->lock_time = SYSTEM_CLOCK_SOURCE_DPLL_LOCK_TIME_DEFAULT; + config->filter = SYSTEM_CLOCK_SOURCE_DPLL_FILTER_DEFAULT; +}; + +void system_clock_source_dpll_set_config( + struct system_clock_source_dpll_config *const config); + +/* @} */ + +/** + * \name System Clock Initialization + * @{ + */ + +void system_clock_init(void); + +/** + * @} + */ + +/** + * \name System Flash Wait States + * @{ + */ + +/** + * \brief Set flash controller wait states. + * + * Will set the number of wait states that are used by the onboard + * flash memory. The number of wait states depend on both device + * supply voltage and CPU speed. The required number of wait states + * can be found in the electrical characteristics of the device. + * + * \param[in] wait_states Number of wait states to use for internal flash + */ +static inline void system_flash_set_waitstates(uint8_t wait_states) +{ + Assert(NVMCTRL_CTRLB_RWS((uint32_t)wait_states) == + ((uint32_t)wait_states << NVMCTRL_CTRLB_RWS_Pos)); + + NVMCTRL->CTRLB.bit.RWS = wait_states; +} +/** + * @} + */ + +/** + * @} + */ + +/** + * \page asfdoc_sam0_system_clock_extra Extra Information for SYSTEM CLOCK Driver + * + * \section asfdoc_sam0_system_clock_extra_acronyms Acronyms + * Below is a table listing the acronyms used in this module, along with their + * intended meanings. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
AcronymDescription
DFLLDigital Frequency Locked Loop
MUXMultiplexer
MCLKMain Clock
OSC32KInternal 32KHz Oscillator
OSC16MInternal 16MHz Oscillator
PLLPhase Locked Loop
OSCOscillator
XOSCExternal Oscillator
XOSC32KExternal 32KHz Oscillator
AHBAdvanced High-performance Bus
APBAdvanced Peripheral Bus
DPLLDigital Phase Locked Loop
+ * + * + * \section asfdoc_sam0_system_clock_extra_dependencies Dependencies + * This driver has the following dependencies: + * + * - None + * + * + * \section asfdoc_sam0_system_clock_extra_errata Errata + * + * - This driver implements experimental workaround for errata 9905 + * + * "The DFLL clock must be requested before being configured. Otherwise a + * write access to a DFLL register can freeze the device." + * This driver will enable and configure the DFLL before the ONDEMAND bit is set. + * + * + * \section asfdoc_sam0_system_clock_extra_history Module History + * An overview of the module history is presented in the table below, with + * details on the enhancements and fixes made to the module since its first + * release. The current version of this corresponds to the newest version in + * the table. + * + * + * + * + * + * + * + * + *
Changelog
Initial Release
+ */ + +/** + * \page asfdoc_sam0_system_clock_exqsg Examples for System Clock Driver + * + * This is a list of the available Quick Start guides (QSGs) and example + * applications for \ref asfdoc_sam0_system_clock_group. QSGs are simple + * examples with step-by-step instructions to configure and use this driver in + * a selection of use cases. Note that a QSG can be compiled as a standalone + * application or be added to the user application. + * + * - \subpage asfdoc_sam0_system_clock_basic_use_case + * - \subpage asfdoc_sam0_system_gclk_basic_use_case + * + * \page asfdoc_sam0_system_clock_document_revision_history Document Revision History + * + * + * + * + * + * + * + * + * + *
Doc. Rev. + * Date + * Comments + *
42452A12/2015Initial document release
+ */ + +#ifdef __cplusplus +} +#endif + +#endif /* SYSTEM_CLOCK_FEATURE_H_INCLUDED */ diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/system/clock/clock_samr34/gclk.c b/src/boards/mcu/samr34/ASF/sam0/drivers/system/clock/clock_samr34/gclk.c new file mode 100644 index 000000000..93bc979ae --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/system/clock/clock_samr34/gclk.c @@ -0,0 +1,454 @@ +/** + * \file + * + * \brief SAMR34 Generic Clock Driver + * + * Copyright (c) 2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#include +#include +#include + + + /** + * \brief Determines if the hardware module(s) are currently synchronizing to the bus. + * + * Checks to see if the underlying hardware peripheral module(s) are currently + * synchronizing across multiple clock domains to the hardware bus, This + * function can be used to delay further operations on a module until such time + * that it is ready, to prevent blocking delays for synchronization in the + * user application. + * \param[in] generator Generic Clock Generator index to sync + * + * \return Synchronization status of the underlying hardware module(s). + * + * \retval false if the module has completed synchronization + * \retval true if the module synchronization is ongoing + */ +static inline bool system_gclk_is_syncing(const uint8_t generator) +{ + + if (GCLK->SYNCBUSY.reg & GCLK_SYNCBUSY_GENCTRL(1 << generator )){ + return true; + } + + return false; +} + + +/** + * \brief Initializes the GCLK driver. + * + * Initializes the Generic Clock module, disabling and resetting all active + * Generic Clock Generators and Channels to their power-on default values. + */ +void system_gclk_init(void) +{ + /* Turn on the digital interface clock */ + system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBA, MCLK_APBAMASK_GCLK); + + /* Software reset the module to ensure it is re-initialized correctly */ + GCLK->CTRLA.reg = GCLK_CTRLA_SWRST; + while (GCLK->CTRLA.reg & GCLK_CTRLA_SWRST) { + /* Wait for reset to complete */ + } +} + +/** + * \brief Writes a Generic Clock Generator configuration to the hardware module. + * + * Writes out a given configuration of a Generic Clock Generator configuration + * to the hardware module. + * + * \note Changing the clock source on the fly (on a running + * generator) can take additional time if the clock source is configured + * to only run on-demand (ONDEMAND bit is set) and it is not currently + * running (no peripheral is requesting the clock source). In this case + * the GCLK will request the new clock while still keeping a request to + * the old clock source until the new clock source is ready. + * + * \note This function will not start a generator that is not already running; + * to start the generator, call \ref system_gclk_gen_enable() + * after configuring a generator. + * + * \param[in] generator Generic Clock Generator index to configure + * \param[in] config Configuration settings for the generator + */ +void system_gclk_gen_set_config( + const uint8_t generator, + struct system_gclk_gen_config *const config) +{ + /* Sanity check arguments */ + Assert(config); + + /* Cache new register configurations to minimize sync requirements. */ + uint32_t new_genctrl_config ; + + + /* Select the requested source clock for the generator */ + new_genctrl_config = config->source_clock << GCLK_GENCTRL_SRC_Pos; + + /* Configure the clock to be either high or low when disabled */ + if (config->high_when_disabled) { + new_genctrl_config |= GCLK_GENCTRL_OOV; + } + + /* Configure if the clock output to I/O pin should be enabled. */ + if (config->output_enable) { + new_genctrl_config |= GCLK_GENCTRL_OE; + } + + /* Set division factor */ + if (config->division_factor > 1) { + /* Check if division is a power of two */ + if (((config->division_factor & (config->division_factor - 1)) == 0)) { + /* Determine the index of the highest bit set to get the + * division factor that must be loaded into the division + * register */ + + uint32_t div2_count = 0; + + uint32_t mask; + for (mask = (1UL << 1); mask < config->division_factor; + mask <<= 1) { + div2_count++; + } + + /* Set binary divider power of 2 division factor */ + new_genctrl_config |= div2_count << GCLK_GENCTRL_DIV_Pos; + new_genctrl_config |= GCLK_GENCTRL_DIVSEL; + } else { + /* Set integer division factor */ + + new_genctrl_config |= + (config->division_factor) << GCLK_GENCTRL_DIV_Pos; + + /* Enable non-binary division with increased duty cycle accuracy */ + new_genctrl_config |= GCLK_GENCTRL_IDC; + } + + } + + /* Enable or disable the clock in standby mode */ + if (config->run_in_standby) { + new_genctrl_config |= GCLK_GENCTRL_RUNSTDBY; + } + + while (system_gclk_is_syncing(generator)) { + /* Wait for synchronization */ + }; + + system_interrupt_enter_critical_section(); + + GCLK->GENCTRL[generator].reg = new_genctrl_config | (GCLK->GENCTRL[generator].reg & GCLK_GENCTRL_GENEN); + + while (system_gclk_is_syncing(generator)) { + /* Wait for synchronization */ + }; + + system_interrupt_leave_critical_section(); +} + +/** + * \brief Enables a Generic Clock Generator that was previously configured. + * + * Starts the clock generation of a Generic Clock Generator that was previously + * configured via a call to \ref system_gclk_gen_set_config(). + * + * \param[in] generator Generic Clock Generator index to enable + */ +void system_gclk_gen_enable( + const uint8_t generator) +{ + while (system_gclk_is_syncing(generator)) { + /* Wait for synchronization */ + }; + + system_interrupt_enter_critical_section(); + + /* Enable generator */ + GCLK->GENCTRL[generator].reg |= GCLK_GENCTRL_GENEN; + + system_interrupt_leave_critical_section(); +} + +/** + * \brief Disables a Generic Clock Generator that was previously enabled. + * + * Stops the clock generation of a Generic Clock Generator that was previously + * started via a call to \ref system_gclk_gen_enable(). + * + * \param[in] generator Generic Clock Generator index to disable + */ +void system_gclk_gen_disable( + const uint8_t generator) +{ + while (system_gclk_is_syncing(generator)) { + /* Wait for synchronization */ + }; + + system_interrupt_enter_critical_section(); + + /* Disable generator */ + GCLK->GENCTRL[generator].reg &= ~GCLK_GENCTRL_GENEN; + while (GCLK->GENCTRL[generator].reg & GCLK_GENCTRL_GENEN) { + /* Wait for clock to become disabled */ + } + + system_interrupt_leave_critical_section(); +} + +/** + * \brief Determins if the specified Generic Clock Generator is enabled. + * + * \param[in] generator Generic Clock Generator index to check + * + * \return The enabled status. + * \retval true The Generic Clock Generator is enabled + * \retval false The Generic Clock Generator is disabled + */ +bool system_gclk_gen_is_enabled( + const uint8_t generator) +{ + bool enabled; + + system_interrupt_enter_critical_section(); + + /* Obtain the enabled status */ + enabled = (GCLK->GENCTRL[generator].reg & GCLK_GENCTRL_GENEN); + + system_interrupt_leave_critical_section(); + + return enabled; +} + +/** + * \brief Retrieves the clock frequency of a Generic Clock generator. + * + * Determines the clock frequency (in Hz) of a specified Generic Clock + * generator, used as a source to a Generic Clock Channel module. + * + * \param[in] generator Generic Clock Generator index + * + * \return The frequency of the generic clock generator, in Hz. + */ +uint32_t system_gclk_gen_get_hz( + const uint8_t generator) +{ + while (system_gclk_is_syncing(generator)) { + /* Wait for synchronization */ + }; + + system_interrupt_enter_critical_section(); + + /* Get the frequency of the source connected to the GCLK generator */ + uint32_t gen_input_hz = system_clock_source_get_hz( + (enum system_clock_source)GCLK->GENCTRL[generator].bit.SRC); + + uint8_t divsel = GCLK->GENCTRL[generator].bit.DIVSEL; + uint32_t divider = GCLK->GENCTRL[generator].bit.DIV; + + system_interrupt_leave_critical_section(); + + /* Check if the generator is using fractional or binary division */ + if (!divsel && divider > 1) { + gen_input_hz /= divider; + } else if (divsel) { + gen_input_hz >>= (divider+1); + } + + return gen_input_hz; +} + +/** + * \brief Writes a Generic Clock configuration to the hardware module. + * + * Writes out a given configuration of a Generic Clock configuration to the + * hardware module. If the clock is currently running, it will be stopped. + * + * \note Once called the clock will not be running; to start the clock, + * call \ref system_gclk_chan_enable() after configuring a clock channel. + * + * \param[in] channel Generic Clock channel to configure + * \param[in] config Configuration settings for the clock + * + */ +void system_gclk_chan_set_config( + const uint8_t channel, + struct system_gclk_chan_config *const config) +{ + /* Sanity check arguments */ + Assert(config); + + /* Disable generic clock channel */ + system_gclk_chan_disable(channel); + + /* Configure the peripheral channel */ + GCLK->PCHCTRL[channel].reg = GCLK_PCHCTRL_GEN(config->source_generator); + + +} + +/** + * \brief Enables a Generic Clock that was previously configured. + * + * Starts the clock generation of a Generic Clock that was previously + * configured via a call to \ref system_gclk_chan_set_config(). + * + * \param[in] channel Generic Clock channel to enable + */ +void system_gclk_chan_enable( + const uint8_t channel) +{ + system_interrupt_enter_critical_section(); + + /* Enable the peripheral channel */ + GCLK->PCHCTRL[channel].reg |= GCLK_PCHCTRL_CHEN; + + while (!(GCLK->PCHCTRL[channel].reg & GCLK_PCHCTRL_CHEN)) { + /* Wait for clock synchronization */ + } + + system_interrupt_leave_critical_section(); +} + +/** + * \brief Disables a Generic Clock that was previously enabled. + * + * Stops the clock generation of a Generic Clock that was previously started + * via a call to \ref system_gclk_chan_enable(). + * + * \param[in] channel Generic Clock channel to disable + */ +void system_gclk_chan_disable( + const uint8_t channel) +{ + system_interrupt_enter_critical_section(); + + /* Sanity check WRTLOCK */ + Assert(!GCLK->PCHCTRL[channel].bit.WRTLOCK); + + /* Disable the peripheral channel */ + GCLK->PCHCTRL[channel].reg &= ~GCLK_PCHCTRL_CHEN; + + while (GCLK->PCHCTRL[channel].reg & GCLK_PCHCTRL_CHEN) { + /* Wait for clock synchronization */ + } + + system_interrupt_leave_critical_section(); +} + +/** + * \brief Determins if the specified Generic Clock channel is enabled. + * + * \param[in] channel Generic Clock Channel index + * + * \return The enabled status. + * \retval true The Generic Clock channel is enabled + * \retval false The Generic Clock channel is disabled + */ +bool system_gclk_chan_is_enabled( + const uint8_t channel) +{ + bool enabled; + + system_interrupt_enter_critical_section(); + + /* Select the requested generic clock channel */ + enabled = GCLK->PCHCTRL[channel].bit.CHEN; + + system_interrupt_leave_critical_section(); + + return enabled; +} + +/** + * \brief Locks a Generic Clock channel from further configuration writes. + * + * Locks a generic clock channel from further configuration writes. It is only + * possible to unlock the channel configuration through a power on reset. + * + * \param[in] channel Generic Clock channel to enable + */ +void system_gclk_chan_lock( + const uint8_t channel) +{ + system_interrupt_enter_critical_section(); + + GCLK->PCHCTRL[channel].reg |= GCLK_PCHCTRL_WRTLOCK | GCLK_PCHCTRL_CHEN; + system_interrupt_leave_critical_section(); +} + +/** + * \brief Determins if the specified Generic Clock channel is locked. + * + * \param[in] channel Generic Clock Channel index + * + * \return The lock status. + * \retval true The Generic Clock channel is locked + * \retval false The Generic Clock channel is not locked + */ +bool system_gclk_chan_is_locked( + const uint8_t channel) +{ + bool locked; + + system_interrupt_enter_critical_section(); + locked = GCLK->PCHCTRL[channel].bit.WRTLOCK; + system_interrupt_leave_critical_section(); + + return locked; +} + +/** + * \brief Retrieves the clock frequency of a Generic Clock channel. + * + * Determines the clock frequency (in Hz) of a specified Generic Clock + * channel, used as a source to a device peripheral module. + * + * \param[in] channel Generic Clock Channel index + * + * \return The frequency of the generic clock channel, in Hz. + */ +uint32_t system_gclk_chan_get_hz( + const uint8_t channel) +{ + uint8_t gen_id; + + system_interrupt_enter_critical_section(); + /* Select the requested generic clock channel */ + gen_id = GCLK->PCHCTRL[channel].bit.GEN; + system_interrupt_leave_critical_section(); + + /* Return the clock speed of the associated GCLK generator */ + return system_gclk_gen_get_hz(gen_id); +} diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/system/clock/gclk.h b/src/boards/mcu/samr34/ASF/sam0/drivers/system/clock/gclk.h new file mode 100644 index 000000000..d082d20be --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/system/clock/gclk.h @@ -0,0 +1,297 @@ +/** + * \file + * + * \brief SAM Generic Clock Driver + * + * Copyright (c) 2012-2020 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#ifndef SYSTEM_CLOCK_GCLK_H_INCLUDED +#define SYSTEM_CLOCK_GCLK_H_INCLUDED + +/** + * \addtogroup asfdoc_sam0_system_clock_group + * + * @{ + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief List of available GCLK generators. + * + * List of Available GCLK generators. This enum is used in the peripheral + * device drivers to select the GCLK generator to be used for its operation. + * + * The number of GCLK generators available is device dependent. + */ +enum gclk_generator { + /** GCLK generator channel 0 */ + GCLK_GENERATOR_0, +#if defined(__DOXYGEN__) || (GCLK_GEN_NUM_MSB > 0) + /** GCLK generator channel 1 */ + GCLK_GENERATOR_1, +#endif +#if defined(__DOXYGEN__) || (GCLK_GEN_NUM_MSB > 1) + /** GCLK generator channel 2 */ + GCLK_GENERATOR_2, +#endif +#if defined(__DOXYGEN__) || (GCLK_GEN_NUM_MSB > 2) + /** GCLK generator channel 3 */ + GCLK_GENERATOR_3, +#endif +#if defined(__DOXYGEN__) || (GCLK_GEN_NUM_MSB > 3) + /** GCLK generator channel 4 */ + GCLK_GENERATOR_4, +#endif +#if defined(__DOXYGEN__) || (GCLK_GEN_NUM_MSB > 4) + /** GCLK generator channel 5 */ + GCLK_GENERATOR_5, +#endif +#if defined(__DOXYGEN__) || (GCLK_GEN_NUM_MSB > 5) + /** GCLK generator channel 6 */ + GCLK_GENERATOR_6, +#endif +#if defined(__DOXYGEN__) || (GCLK_GEN_NUM_MSB > 6) + /** GCLK generator channel 7 */ + GCLK_GENERATOR_7, +#endif +#if defined(__DOXYGEN__) || (GCLK_GEN_NUM_MSB > 7) + /** GCLK generator channel 8 */ + GCLK_GENERATOR_8, +#endif +#if defined(__DOXYGEN__) || (GCLK_GEN_NUM_MSB > 8) + /** GCLK generator channel 9 */ + GCLK_GENERATOR_9, +#endif +#if defined(__DOXYGEN__) || (GCLK_GEN_NUM_MSB > 9) + /** GCLK generator channel 10 */ + GCLK_GENERATOR_10, +#endif +#if defined(__DOXYGEN__) || (GCLK_GEN_NUM_MSB > 10) + /** GCLK generator channel 11 */ + GCLK_GENERATOR_11, +#endif +#if defined(__DOXYGEN__) || (GCLK_GEN_NUM_MSB > 11) + /** GCLK generator channel 12 */ + GCLK_GENERATOR_12, +#endif +#if defined(__DOXYGEN__) || (GCLK_GEN_NUM_MSB > 12) + /** GCLK generator channel 13 */ + GCLK_GENERATOR_13, +#endif +#if defined(__DOXYGEN__) || (GCLK_GEN_NUM_MSB > 13) + /** GCLK generator channel 14 */ + GCLK_GENERATOR_14, +#endif +#if defined(__DOXYGEN__) || (GCLK_GEN_NUM_MSB > 14) + /** GCLK generator channel 15 */ + GCLK_GENERATOR_15, +#endif +#if defined(__DOXYGEN__) || (GCLK_GEN_NUM_MSB > 15) + /** GCLK generator channel 16 */ + GCLK_GENERATOR_16, +#endif +}; + +/** + * \brief Generic Clock Generator configuration structure. + * + * Configuration structure for a Generic Clock Generator channel. This + * structure should be initialized by the + * \ref system_gclk_gen_get_config_defaults() function before being modified by + * the user application. + */ +struct system_gclk_gen_config { + /** Source clock input channel index, see the \ref system_clock_source */ + uint8_t source_clock; + /** If \c true, the generator output level is high when disabled */ + bool high_when_disabled; + /** Integer division factor of the clock output compared to the input */ + uint32_t division_factor; + /** If \c true, the clock is kept enabled during device standby mode */ + bool run_in_standby; + /** If \c true, enables GCLK generator clock output to a GPIO pin */ + bool output_enable; +}; + +/** + * \brief Generic Clock configuration structure. + * + * Configuration structure for a Generic Clock channel. This structure + * should be initialized by the \ref system_gclk_chan_get_config_defaults() + * function before being modified by the user application. + */ +struct system_gclk_chan_config { + /** Generic Clock Generator source channel */ + enum gclk_generator source_generator; +}; + +/** \name Generic Clock Management + * @{ + */ +void system_gclk_init(void); + +/** @} */ + + +/** + * \name Generic Clock Management (Generators) + * @{ + */ + +/** + * \brief Initializes a Generic Clock Generator configuration structure to defaults. + * + * Initializes a given Generic Clock Generator configuration structure to + * a set of known default values. This function should be called on all + * new instances of these configuration structures before being modified + * by the user application. + * + * The default configuration is: + * \li The clock is generated undivided from the source frequency + * \li The clock generator output is low when the generator is disabled + * \li The input clock is sourced from input clock channel 0 + * \li The clock will be disabled during sleep + * \li The clock output will not be routed to a physical GPIO pin + * + * \param[out] config Configuration structure to initialize to default values + */ +static inline void system_gclk_gen_get_config_defaults( + struct system_gclk_gen_config *const config) +{ + /* Sanity check arguments */ + Assert(config); + + /* Default configuration values */ + config->division_factor = 1; + config->high_when_disabled = false; +#if SAML21 || SAML22 || SAMR30 || SAMR34 || SAMR35 || (WLR089) + config->source_clock = GCLK_SOURCE_OSC16M; +#elif (SAMC20) || (SAMC21) + config->source_clock = GCLK_SOURCE_OSC48M; +#else + config->source_clock = GCLK_SOURCE_OSC8M; +#endif + config->run_in_standby = false; + config->output_enable = false; +} + +void system_gclk_gen_set_config( + const uint8_t generator, + struct system_gclk_gen_config *const config); + +void system_gclk_gen_enable( + const uint8_t generator); + +void system_gclk_gen_disable( + const uint8_t generator); + +bool system_gclk_gen_is_enabled( + const uint8_t generator); + +/** @} */ + + +/** + * \name Generic Clock Management (Channels) + * @{ + */ + +/** + * \brief Initializes a Generic Clock configuration structure to defaults. + * + * Initializes a given Generic Clock configuration structure to a set of + * known default values. This function should be called on all new + * instances of these configuration structures before being modified by the + * user application. + * + * The default configuration is as follows: + * \li The clock is sourced from the Generic Clock Generator channel 0 + * \li The clock configuration will not be write-locked when set + * + * \param[out] config Configuration structure to initialize to default values + */ +static inline void system_gclk_chan_get_config_defaults( + struct system_gclk_chan_config *const config) +{ + /* Sanity check arguments */ + Assert(config); + + /* Default configuration values */ + config->source_generator = GCLK_GENERATOR_0; +} + +void system_gclk_chan_set_config( + const uint8_t channel, + struct system_gclk_chan_config *const config); + +void system_gclk_chan_enable( + const uint8_t channel); + +void system_gclk_chan_disable( + const uint8_t channel); + +bool system_gclk_chan_is_enabled( + const uint8_t channel); + +void system_gclk_chan_lock( + const uint8_t channel); + +bool system_gclk_chan_is_locked( + const uint8_t channel); + +/** @} */ + + +/** + * \name Generic Clock Frequency Retrieval + * @{ + */ + +uint32_t system_gclk_gen_get_hz( + const uint8_t generator); + +uint32_t system_gclk_chan_get_hz( + const uint8_t channel); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/system/interrupt/system_interrupt.c b/src/boards/mcu/samr34/ASF/sam0/drivers/system/interrupt/system_interrupt.c new file mode 100644 index 000000000..126f7d404 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/system/interrupt/system_interrupt.c @@ -0,0 +1,207 @@ +/** + * \file + * + * \brief SAM System Interrupt Driver + * + * Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#include "system_interrupt.h" + +/** + * \brief Check if a interrupt line is pending. + * + * Checks if the requested interrupt vector is pending. + * + * \param[in] vector Interrupt vector number to check + * + * \returns A boolean identifying if the requested interrupt vector is pending. + * + * \retval true Specified interrupt vector is pending + * \retval false Specified interrupt vector is not pending + * + */ +bool system_interrupt_is_pending( + const enum system_interrupt_vector vector) +{ + bool result; + + if (vector >= _SYSTEM_INTERRUPT_EXTERNAL_VECTOR_START) { + result = ((NVIC->ISPR[0] & (1 << vector)) != 0); + } else if (vector == SYSTEM_INTERRUPT_SYSTICK) { + result = ((SCB->ICSR & SCB_ICSR_PENDSTSET_Msk) != 0); + } else { + Assert(false); + result = false; + } + + return result; +} + +/** + * \brief Set a interrupt vector as pending. + * + * Set the requested interrupt vector as pending (i.e. issues a software + * interrupt request for the specified vector). The software handler will be + * handled (if enabled) in a priority order based on vector number and + * configured priority settings. + * + * \param[in] vector Interrupt vector number which is set as pending + * + * \returns Status code identifying if the vector was successfully set as + * pending. + * + * \retval STATUS_OK If no error was detected + * \retval STATUS_INVALID_ARG If an unsupported interrupt vector number was given + */ +enum status_code system_interrupt_set_pending( + const enum system_interrupt_vector vector) +{ + enum status_code status = STATUS_OK; + + if (vector >= _SYSTEM_INTERRUPT_EXTERNAL_VECTOR_START) { + NVIC->ISPR[0] = (1 << vector); + } else if (vector == SYSTEM_INTERRUPT_NON_MASKABLE) { + /* Note: Because NMI has highest priority it will be executed + * immediately after it has been set pending */ + SCB->ICSR = SCB_ICSR_NMIPENDSET_Msk; + } else if (vector == SYSTEM_INTERRUPT_SYSTICK) { + SCB->ICSR = SCB_ICSR_PENDSTSET_Msk; + } else { + /* The user want to set something unsupported as pending */ + Assert(false); + status = STATUS_ERR_INVALID_ARG; + } + + return status; +} + +/** + * \brief Clear pending interrupt vector. + * + * Clear a pending interrupt vector, so the software handler is not executed. + * + * \param[in] vector Interrupt vector number to clear + * + * \returns A status code identifying if the interrupt pending state was + * successfully cleared. + * + * \retval STATUS_OK If no error was detected + * \retval STATUS_INVALID_ARG If an unsupported interrupt vector number was given + */ +enum status_code system_interrupt_clear_pending( + const enum system_interrupt_vector vector) +{ + enum status_code status = STATUS_OK; + + if (vector >= _SYSTEM_INTERRUPT_EXTERNAL_VECTOR_START) { + NVIC->ICPR[0] = (1 << vector); + } else if (vector == SYSTEM_INTERRUPT_NON_MASKABLE) { + /* Note: Clearing of NMI pending interrupts does not make sense and is + * not supported by the device, as it has the highest priority and will + * always be executed at the moment it is set */ + return STATUS_ERR_INVALID_ARG; + } else if (vector == SYSTEM_INTERRUPT_SYSTICK) { + SCB->ICSR = SCB_ICSR_PENDSTCLR_Msk; + } else { + Assert(false); + status = STATUS_ERR_INVALID_ARG; + } + + return status; +} + +/** + * \brief Set interrupt vector priority level. + * + * Set the priority level of an external interrupt or exception. + * + * \param[in] vector Interrupt vector to change + * \param[in] priority_level New vector priority level to set + * + * \returns Status code indicating if the priority level of the interrupt was + * successfully set. + * + * \retval STATUS_OK If no error was detected + * \retval STATUS_INVALID_ARG If an unsupported interrupt vector number was given + */ +enum status_code system_interrupt_set_priority( + const enum system_interrupt_vector vector, + const enum system_interrupt_priority_level priority_level) +{ + enum status_code status = STATUS_OK; + + if (vector >= _SYSTEM_INTERRUPT_EXTERNAL_VECTOR_START) { + uint8_t register_num = vector / 4; + uint8_t priority_pos = ((vector % 4) * 8) + (8 - __NVIC_PRIO_BITS); + + NVIC->IP[register_num] = + (NVIC->IP[register_num] & ~(_SYSTEM_INTERRUPT_PRIORITY_MASK << priority_pos)) | + (priority_level << priority_pos); + + } else if (vector == SYSTEM_INTERRUPT_SYSTICK) { + SCB->SHP[1] = (priority_level << _SYSTEM_INTERRUPT_SYSTICK_PRI_POS); + } else { + Assert(false); + status = STATUS_ERR_INVALID_ARG; + } + + return status; +} + +/** + * \brief Get interrupt vector priority level. + * + * Retrieves the priority level of the requested external interrupt or exception. + * + * \param[in] vector Interrupt vector of which the priority level will be read + * + * \return Currently configured interrupt priority level of the given interrupt + * vector. + */ +enum system_interrupt_priority_level system_interrupt_get_priority( + const enum system_interrupt_vector vector) +{ + uint8_t register_num = vector / 4; + uint8_t priority_pos = ((vector % 4) * 8) + (8 - __NVIC_PRIO_BITS); + + enum system_interrupt_priority_level priority = SYSTEM_INTERRUPT_PRIORITY_LEVEL_0; + + if (vector >= 0) { + priority = (enum system_interrupt_priority_level) + ((NVIC->IP[register_num] >> priority_pos) & _SYSTEM_INTERRUPT_PRIORITY_MASK); + } else if (vector == SYSTEM_INTERRUPT_SYSTICK) { + priority = (enum system_interrupt_priority_level) + ((SCB->SHP[1] >> _SYSTEM_INTERRUPT_SYSTICK_PRI_POS) & _SYSTEM_INTERRUPT_PRIORITY_MASK); + } + + return priority; +} + diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/system/interrupt/system_interrupt.h b/src/boards/mcu/samr34/ASF/sam0/drivers/system/interrupt/system_interrupt.h new file mode 100644 index 000000000..6cbe534de --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/system/interrupt/system_interrupt.h @@ -0,0 +1,423 @@ +/** + * \file + * + * \brief SAM System Interrupt Driver + * + * Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#ifndef SYSTEM_INTERRUPT_H_INCLUDED +#define SYSTEM_INTERRUPT_H_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup asfdoc_sam0_system_interrupt_group SAM System Interrupt (SYSTEM INTERRUPT) Driver + * + * This driver for Atmel® | SMART ARM®-based microcontrollers provides + * an interface for the configuration and management of internal software and + * hardware interrupts/exceptions. + * + * The following peripheral is used by this module: + * - NVIC (Nested Vector Interrupt Controller) + * + * The following devices can use this module: + * - Atmel | SMART SAM D20/D21 + * - Atmel | SMART SAM R21 + * - Atmel | SMART SAM D09/D10/D11 + * - Atmel | SMART SAM L21/L22 + * - Atmel | SMART SAM DA1 + * - Atmel | SMART SAM C20/C21 + * - Atmel | SMART SAM HA1 + * - Atmel | SMART SAM R30 + * - Atmel | SMART SAM R34 + * - Atmel | SMART SAM R35 + * + * The outline of this documentation is as follows: + * - \ref asfdoc_sam0_system_interrupt_prerequisites + * - \ref asfdoc_sam0_system_interrupt_module_overview + * - \ref asfdoc_sam0_system_interrupt_special_considerations + * - \ref asfdoc_sam0_system_interrupt_extra_info + * - \ref asfdoc_sam0_system_interrupt_examples + * - \ref asfdoc_sam0_system_interrupt_api_overview + * + * + * \section asfdoc_sam0_system_interrupt_prerequisites Prerequisites + * + * There are no prerequisites for this module. + * + * + * \section asfdoc_sam0_system_interrupt_module_overview Module Overview + * + * The ARM® Cortex® M0+ core contains an interrupt and exception vector table, which + * can be used to configure the device's interrupt handlers; individual + * interrupts and exceptions can be enabled and disabled, as well as configured + * with a variable priority. + * + * This driver provides a set of wrappers around the core interrupt functions, + * to expose a simple API for the management of global and individual interrupts + * within the device. + * + * \subsection asfdoc_sam0_system_interrupt_module_overview_criticalsec Critical Sections + * In some applications it is important to ensure that no interrupts may be + * executed by the system whilst a critical portion of code is being run; for + * example, a buffer may be copied from one context to another - during which + * interrupts must be disabled to avoid corruption of the source buffer contents + * until the copy has completed. This driver provides a basic API to enter and + * exit nested critical sections, so that global interrupts can be kept disabled + * for as long as necessary to complete a critical application code section. + * + * \subsection asfdoc_sam0_system_interrupt_module_overview_softints Software Interrupts + * For some applications, it may be desirable to raise a module or core + * interrupt via software. For this reason, a set of APIs to set an interrupt or + * exception as pending are provided to the user application. + * + * \section asfdoc_sam0_system_interrupt_special_considerations Special Considerations + * + * Interrupts from peripherals in the SAM devices are on a per-module basis; + * an interrupt raised from any source within a module will cause a single, + * module-common handler to execute. It is the user application or driver's + * responsibility to de-multiplex the module-common interrupt to determine the + * exact interrupt cause. + * + * \section asfdoc_sam0_system_interrupt_extra_info Extra Information + * + * For extra information, see \ref asfdoc_sam0_system_interrupt_extra. This includes: + * - \ref asfdoc_sam0_system_interrupt_extra_acronyms + * - \ref asfdoc_sam0_system_interrupt_extra_dependencies + * - \ref asfdoc_sam0_system_interrupt_extra_errata + * - \ref asfdoc_sam0_system_interrupt_extra_history + * + * + * \section asfdoc_sam0_system_interrupt_examples Examples + * + * For a list of examples related to this driver, see + * \ref asfdoc_sam0_system_interrupt_exqsg. + * + * \section asfdoc_sam0_system_interrupt_api_overview API Overview + * @{ + */ + +#include +#include +#include "system_interrupt_features.h" + +/** + * \brief Table of possible system interrupt/exception vector priorities. + * + * Table of all possible interrupt and exception vector priorities within the + * device. + */ +enum system_interrupt_priority_level { + /** Priority level 0, the highest possible interrupt priority */ + SYSTEM_INTERRUPT_PRIORITY_LEVEL_0 = 0, + /** Priority level 1 */ + SYSTEM_INTERRUPT_PRIORITY_LEVEL_1 = 1, + /** Priority level 2 */ + SYSTEM_INTERRUPT_PRIORITY_LEVEL_2 = 2, + /** Priority level 3, the lowest possible interrupt priority */ + SYSTEM_INTERRUPT_PRIORITY_LEVEL_3 = 3, +}; + +/** + * \name Critical Section Management + * @{ + */ + +/** + * \brief Enters a critical section. + * + * Disables global interrupts. To support nested critical sections, an internal + * count of the critical section nesting will be kept, so that global interrupts + * are only re-enabled upon leaving the outermost nested critical section. + * + */ +static inline void system_interrupt_enter_critical_section(void) +{ + cpu_irq_enter_critical(); +} + +/** + * \brief Leaves a critical section. + * + * Enables global interrupts. To support nested critical sections, an internal + * count of the critical section nesting will be kept, so that global interrupts + * are only re-enabled upon leaving the outermost nested critical section. + * + */ +static inline void system_interrupt_leave_critical_section(void) +{ + cpu_irq_leave_critical(); +} + +/** @} */ + +/** + * \name Interrupt Enabling/Disabling + * @{ + */ + +/** + * \brief Check if global interrupts are enabled. + * + * Checks if global interrupts are currently enabled. + * + * \returns A boolean that identifies if the global interrupts are enabled or not. + * + * \retval true Global interrupts are currently enabled + * \retval false Global interrupts are currently disabled + * + */ +static inline bool system_interrupt_is_global_enabled(void) +{ + return cpu_irq_is_enabled(); +} + +/** + * \brief Enables global interrupts. + * + * Enables global interrupts in the device to fire any enabled interrupt handlers. + */ +static inline void system_interrupt_enable_global(void) +{ + cpu_irq_enable(); +} + +/** + * \brief Disables global interrupts. + * + * Disabled global interrupts in the device, preventing any enabled interrupt + * handlers from executing. + */ +static inline void system_interrupt_disable_global(void) +{ + cpu_irq_disable(); +} + +/** + * \brief Checks if an interrupt vector is enabled or not. + * + * Checks if a specific interrupt vector is currently enabled. + * + * \param[in] vector Interrupt vector number to check + * + * \returns A variable identifying if the requested interrupt vector is enabled. + * + * \retval true Specified interrupt vector is currently enabled + * \retval false Specified interrupt vector is currently disabled + * + */ +static inline bool system_interrupt_is_enabled( + const enum system_interrupt_vector vector) +{ + return (bool)((NVIC->ISER[0] >> (uint32_t)vector) & 0x00000001); +} + +/** + * \brief Enable interrupt vector. + * + * Enables execution of the software handler for the requested interrupt vector. + * + * \param[in] vector Interrupt vector to enable + */ +static inline void system_interrupt_enable( + const enum system_interrupt_vector vector) +{ + NVIC->ISER[0] = (uint32_t)(1 << ((uint32_t)vector & 0x0000001f)); +} + +/** + * \brief Disable interrupt vector. + * + * Disables execution of the software handler for the requested interrupt vector. + * + * \param[in] vector Interrupt vector to disable + */ +static inline void system_interrupt_disable( + const enum system_interrupt_vector vector) +{ + NVIC->ICER[0] = (uint32_t)(1 << ((uint32_t)vector & 0x0000001f)); +} + +/** @} */ + +/** + * \name Interrupt State Management + * @{ + */ + +/** + * \brief Get active interrupt (if any). + * + * Return the vector number for the current executing software handler, if any. + * + * \return Interrupt number that is currently executing. + */ +static inline enum system_interrupt_vector system_interrupt_get_active(void) +{ + uint32_t IPSR = __get_IPSR(); + /* The IPSR returns the Exception number, which with an offset 16 to IRQ number. */ + return (enum system_interrupt_vector)((IPSR & _SYSTEM_INTERRUPT_IPSR_MASK) - 16); +} + +bool system_interrupt_is_pending( + const enum system_interrupt_vector vector); + +enum status_code system_interrupt_set_pending( + const enum system_interrupt_vector vector); + +enum status_code system_interrupt_clear_pending( + const enum system_interrupt_vector vector); + +/** @} */ + +/** + * \name Interrupt Priority Management + * @{ + */ + +enum status_code system_interrupt_set_priority( + const enum system_interrupt_vector vector, + const enum system_interrupt_priority_level priority_level); + +enum system_interrupt_priority_level system_interrupt_get_priority( + const enum system_interrupt_vector vector); + +/** @} */ + +/** @} */ + +/** + * \page asfdoc_sam0_system_interrupt_extra Extra Information for SYSTEM INTERRUPT Driver + * + * \section asfdoc_sam0_system_interrupt_extra_acronyms Acronyms + * The table below presents the acronyms used in this module: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
AcronymDescription
ISRInterrupt Service Routine
NMINon-maskable Interrupt
SERCOMSerial Communication Interface
+ * + * + * \section asfdoc_sam0_system_interrupt_extra_dependencies Dependencies + * This driver has the following dependencies: + * + * - None + * + * + * \section asfdoc_sam0_system_interrupt_extra_errata Errata + * There are no errata related to this driver. + * + * + * \section asfdoc_sam0_system_interrupt_extra_history Module History + * An overview of the module history is presented in the table below, with + * details on the enhancements and fixes made to the module since its first + * release. The current version of this corresponds to the newest version in + * the table. + * + * + * + * + * + * + * + * + *
Changelog
Initial Release
+ */ + +/** + * \page asfdoc_sam0_system_interrupt_exqsg Examples for SYSTEM INTERRUPT Driver + * + * This is a list of the available Quick Start guides (QSGs) and example + * applications for \ref asfdoc_sam0_system_interrupt_group. QSGs are simple examples with + * step-by-step instructions to configure and use this driver in a selection of + * use cases. Note that a QSG can be compiled as a standalone application or be + * added to the user application. + * + * - \subpage asfdoc_sam0_system_interrupt_critsec_use_case + * - \subpage asfdoc_sam0_system_interrupt_enablemodint_use_case + * + * \page asfdoc_sam0_system_interrupt_document_revision_history Document Revision History + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Doc. Rev.DateComments
42122E12/2015Added support for SAM L21/L22, SAM DA1, SAM D09, and SAM C20/C21
42122D12/2014Added support for SAM R21 and SAM D10/D11
42122C01/2014Added support for SAM D21
42122B06/2013Corrected documentation typos
42122A06/2013Initial release
+ */ + +#ifdef __cplusplus +} +#endif + +#endif // #ifndef SYSTEM_INTERRUPT_H_INCLUDED diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/system/interrupt/system_interrupt_samr34/system_interrupt_features.h b/src/boards/mcu/samr34/ASF/sam0/drivers/system/interrupt/system_interrupt_samr34/system_interrupt_features.h new file mode 100644 index 000000000..a0efee43e --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/system/interrupt/system_interrupt_samr34/system_interrupt_features.h @@ -0,0 +1,158 @@ +/** + * \file + * + * \brief SAMR34 System Interrupt Driver + * + * Copyright (c) 2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#ifndef SYSTEM_INTERRUPT_FEATURES_H_INCLUDED +#define SYSTEM_INTERRUPT_FEATURES_H_INCLUDED + +#if !defined(__DOXYGEN__) + +/* Generates a interrupt vector table enum list entry for a given module type + and index (e.g. "SYSTEM_INTERRUPT_MODULE_TC0 = TC0_IRQn,"). */ +# define _MODULE_IRQn(n, module) \ + SYSTEM_INTERRUPT_MODULE_##module##n = module##n##_IRQn, + +/* Generates interrupt vector table enum list entries for all instances of a + given module type on the selected device. */ +# define _SYSTEM_INTERRUPT_MODULES(name) \ + MREPEAT(name##_INST_NUM, _MODULE_IRQn, name) + +# define _SYSTEM_INTERRUPT_IPSR_MASK 0x0000003f +# define _SYSTEM_INTERRUPT_PRIORITY_MASK 0x00000003 + +# define _SYSTEM_INTERRUPT_EXTERNAL_VECTOR_START 0 + +# define _SYSTEM_INTERRUPT_SYSTICK_PRI_POS 30 +#endif + +/** + * \addtogroup asfdoc_sam0_system_interrupt_group + * @{ + */ + +/** + * \brief Table of possible system interrupt/exception vector numbers. + * + * Table of all possible interrupt and exception vector indexes within the + * SAM L21 device. + */ +#if defined(__DOXYGEN__) +/** \note The actual enumeration name is "system_interrupt_vector". */ +enum system_interrupt_vector_samr34 { +#else +enum system_interrupt_vector { +#endif + /** Interrupt vector index for a NMI interrupt */ + SYSTEM_INTERRUPT_NON_MASKABLE = NonMaskableInt_IRQn, + /** Interrupt vector index for a Hard Fault memory access exception */ + SYSTEM_INTERRUPT_HARD_FAULT = HardFault_IRQn, + /** Interrupt vector index for a Supervisor Call exception */ + SYSTEM_INTERRUPT_SV_CALL = SVCall_IRQn, + /** Interrupt vector index for a Pending Supervisor interrupt */ + SYSTEM_INTERRUPT_PENDING_SV = PendSV_IRQn, + /** Interrupt vector index for a System Tick interrupt */ + SYSTEM_INTERRUPT_SYSTICK = SysTick_IRQn, + + /** Interrupt vector index for MCLK, OSCCTRL, OSC32KCTRL, PAC, PM, SUPC, TAL peripheral interrupt */ + SYSTEM_INTERRUPT_MODULE_SYSTEM = SYSTEM_IRQn, + /** Interrupt vector index for a Watch Dog peripheral interrupt */ + SYSTEM_INTERRUPT_MODULE_WDT = WDT_IRQn, + /** Interrupt vector index for a Real Time Clock peripheral interrupt */ + SYSTEM_INTERRUPT_MODULE_RTC = RTC_IRQn, + /** Interrupt vector index for an External Interrupt peripheral interrupt */ + SYSTEM_INTERRUPT_MODULE_EIC = EIC_IRQn, + /** Interrupt vector index for a Non Volatile Memory Controller interrupt */ + SYSTEM_INTERRUPT_MODULE_NVMCTRL = NVMCTRL_IRQn, + /** Interrupt vector index for a Direct Memory Access interrupt */ + SYSTEM_INTERRUPT_MODULE_DMA = DMAC_IRQn, + /** Interrupt vector index for a Universal Serial Bus interrupt */ + SYSTEM_INTERRUPT_MODULE_USB = USB_IRQn, + /** Interrupt vector index for an Event System interrupt */ + SYSTEM_INTERRUPT_MODULE_EVSYS = EVSYS_IRQn, +#if defined(__DOXYGEN__) + /** Interrupt vector index for a SERCOM peripheral interrupt. + * + * Each specific device may contain several SERCOM peripherals; each module + * instance will have its own entry in the table, with the instance number + * substituted for "n" in the entry name (e.g. + * \c SYSTEM_INTERRUPT_MODULE_SERCOM0). + */ + SYSTEM_INTERRUPT_MODULE_SERCOMn = SERCOMn_IRQn, + + /** Interrupt vector index for a Timer/Counter Control peripheral interrupt. + * + * Each specific device may contain several TCC peripherals; each module + * instance will have its own entry in the table, with the instance number + * substituted for "n" in the entry name (e.g. + * \c SYSTEM_INTERRUPT_MODULE_TCC0). + */ + SYSTEM_INTERRUPT_MODULE_TCCn = TCCn_IRQn, + + /** Interrupt vector index for a Timer/Counter peripheral interrupt. + * + * Each specific device may contain several TC peripherals; each module + * instance will have its own entry in the table, with the instance number + * substituted for "n" in the entry name (e.g. + * \c SYSTEM_INTERRUPT_MODULE_TC3). + */ + SYSTEM_INTERRUPT_MODULE_TCn = TCn_IRQn, +#else + _SYSTEM_INTERRUPT_MODULES(SERCOM) + + _SYSTEM_INTERRUPT_MODULES(TCC) +#if (SAML21J) || (SAMR34J) || (SAMR35J) + _SYSTEM_INTERRUPT_MODULES(TC) +#else + SYSTEM_INTERRUPT_MODULE_TC0 = TC0_IRQn, + SYSTEM_INTERRUPT_MODULE_TC1 = TC1_IRQn, + SYSTEM_INTERRUPT_MODULE_TC4 = TC4_IRQn, +#endif +#endif + + /** Interrupt vector index for an Analog Comparator peripheral interrupt */ + SYSTEM_INTERRUPT_MODULE_AC = AC_IRQn, + /** Interrupt vector index for an Analog-to-Digital peripheral interrupt */ + SYSTEM_INTERRUPT_MODULE_ADC = ADC_IRQn, + /** Interrupt vector index for a Peripheral Touch Controller peripheral interrupt */ + SYSTEM_INTERRUPT_MODULE_PTC = PTC_IRQn, + /** Interrupt vector index for a AES peripheral interrupt */ + SYSTEM_INTERRUPT_MODULE_AES = AES_IRQn, + /** Interrupt vector index for a TRNG peripheral interrupt */ + SYSTEM_INTERRUPT_MODULE_TRNG = TRNG_IRQn, +}; + +/** @} */ + +#endif diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/system/pinmux/pinmux.c b/src/boards/mcu/samr34/ASF/sam0/drivers/system/pinmux/pinmux.c new file mode 100644 index 000000000..5dfe73d6f --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/system/pinmux/pinmux.c @@ -0,0 +1,301 @@ +/** + * \file + * + * \brief SAM Pin Multiplexer Driver + * + * Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#include + +/** + * \internal + * Writes out a given configuration of a Port pin configuration to the + * hardware module. + * + * \note If the pin direction is set as an output, the pull-up/pull-down input + * configuration setting is ignored. + * + * \param[in] port Base of the PORT module to configure + * \param[in] pin_mask Mask of the port pin to configure + * \param[in] config Configuration settings for the pin + */ +static void _system_pinmux_config( + PortGroup *const port, + const uint32_t pin_mask, + const struct system_pinmux_config *const config) +{ + Assert(port); + Assert(config); + + /* Track the configuration bits into a temporary variable before writing */ + uint32_t pin_cfg = 0; + + /* Enabled powersave mode, don't create configuration */ + if (!config->powersave) { + /* Enable the pin peripheral MUX flag if non-GPIO selected (pinmux will + * be written later) and store the new MUX mask */ + if (config->mux_position != SYSTEM_PINMUX_GPIO) { + pin_cfg |= PORT_WRCONFIG_PMUXEN; + pin_cfg |= (config->mux_position << PORT_WRCONFIG_PMUX_Pos); + } + + /* Check if the user has requested that the input buffer be enabled */ + if ((config->direction == SYSTEM_PINMUX_PIN_DIR_INPUT) || + (config->direction == SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK)) { + /* Enable input buffer flag */ + pin_cfg |= PORT_WRCONFIG_INEN; + + /* Enable pull-up/pull-down control flag if requested */ + if (config->input_pull != SYSTEM_PINMUX_PIN_PULL_NONE) { + pin_cfg |= PORT_WRCONFIG_PULLEN; + } + + /* Clear the port DIR bits to disable the output buffer */ + port->DIRCLR.reg = pin_mask; + } + + /* Check if the user has requested that the output buffer be enabled */ + if ((config->direction == SYSTEM_PINMUX_PIN_DIR_OUTPUT) || + (config->direction == SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK)) { + /* Cannot use a pull-up if the output driver is enabled, + * if requested the input buffer can only sample the current + * output state */ + pin_cfg &= ~PORT_WRCONFIG_PULLEN; + } + } else { + port->DIRCLR.reg = pin_mask; + } + + /* The Write Configuration register (WRCONFIG) requires the + * pins to to grouped into two 16-bit half-words - split them out here */ + uint32_t lower_pin_mask = (pin_mask & 0xFFFF); + uint32_t upper_pin_mask = (pin_mask >> 16); + + /* Configure the lower 16-bits of the port to the desired configuration, + * including the pin peripheral multiplexer just in case it is enabled */ + port->WRCONFIG.reg + = (lower_pin_mask << PORT_WRCONFIG_PINMASK_Pos) | + pin_cfg | PORT_WRCONFIG_WRPMUX | PORT_WRCONFIG_WRPINCFG; + + /* Configure the upper 16-bits of the port to the desired configuration, + * including the pin peripheral multiplexer just in case it is enabled */ + port->WRCONFIG.reg + = (upper_pin_mask << PORT_WRCONFIG_PINMASK_Pos) | + pin_cfg | PORT_WRCONFIG_WRPMUX | PORT_WRCONFIG_WRPINCFG | + PORT_WRCONFIG_HWSEL; + + if(!config->powersave) { + /* Set the pull-up state once the port pins are configured if one was + * requested and it does not violate the valid set of port + * configurations */ + if (pin_cfg & PORT_WRCONFIG_PULLEN) { + /* Set the OUT register bits to enable the pull-up if requested, + * clear to enable pull-down */ + if (config->input_pull == SYSTEM_PINMUX_PIN_PULL_UP) { + port->OUTSET.reg = pin_mask; + } else { + port->OUTCLR.reg = pin_mask; + } + } + + /* Check if the user has requested that the output buffer be enabled */ + if ((config->direction == SYSTEM_PINMUX_PIN_DIR_OUTPUT) || + (config->direction == SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK)) { + /* Set the port DIR bits to enable the output buffer */ + port->DIRSET.reg = pin_mask; + } + } +} + +/** + * \brief Writes a Port pin configuration to the hardware module. + * + * Writes out a given configuration of a Port pin configuration to the hardware + * module. + * + * \note If the pin direction is set as an output, the pull-up/pull-down input + * configuration setting is ignored. + * + * \param[in] gpio_pin Index of the GPIO pin to configure + * \param[in] config Configuration settings for the pin + */ +void system_pinmux_pin_set_config( + const uint8_t gpio_pin, + const struct system_pinmux_config *const config) +{ + PortGroup *const port = system_pinmux_get_group_from_gpio_pin(gpio_pin); + uint32_t pin_mask = (1UL << (gpio_pin % 32)); + + _system_pinmux_config(port, pin_mask, config); +} + +/** + * \brief Writes a Port pin group configuration to the hardware module. + * + * Writes out a given configuration of a Port pin group configuration to the + * hardware module. + * + * \note If the pin direction is set as an output, the pull-up/pull-down input + * configuration setting is ignored. + * + * \param[in] port Base of the PORT module to configure + * \param[in] mask Mask of the port pin(s) to configure + * \param[in] config Configuration settings for the pin + */ +void system_pinmux_group_set_config( + PortGroup *const port, + const uint32_t mask, + const struct system_pinmux_config *const config) +{ + Assert(port); + + for (int i = 0; i < 32; i++) { + if (mask & (1UL << i)) { + _system_pinmux_config(port, (1UL << i), config); + } + } +} + +/** + * \brief Configures the input sampling mode for a group of pins. + * + * Configures the input sampling mode for a group of pins, to + * control when the physical I/O pin value is sampled and + * stored inside the microcontroller. + * + * \param[in] port Base of the PORT module to configure + * \param[in] mask Mask of the port pin(s) to configure + * \param[in] mode New pin sampling mode to configure + */ +void system_pinmux_group_set_input_sample_mode( + PortGroup *const port, + const uint32_t mask, + const enum system_pinmux_pin_sample mode) +{ + Assert(port); + + if (mode == SYSTEM_PINMUX_PIN_SAMPLE_ONDEMAND) { + port->CTRL.reg |= mask; + } else { + port->CTRL.reg &= ~mask; + } +} + +#ifdef FEATURE_SYSTEM_PINMUX_SLEWRATE_LIMITER +/** + * \brief Configures the output slew rate mode for a group of pins. + * + * Configures the output slew rate mode for a group of pins, to + * control the speed at which the physical output pin can react to + * logical changes of the I/O pin value. + * + * \param[in] port Base of the PORT module to configure + * \param[in] mask Mask of the port pin(s) to configure + * \param[in] mode New pin slew rate mode to configure + */ +void system_pinmux_group_set_output_slew_rate( + PortGroup *const port, + const uint32_t mask, + const enum system_pinmux_pin_slew_rate mode) +{ + Assert(port); + + for (int i = 0; i < 32; i++) { + if (mask & (1UL << i)) { + if (mode == SYSTEM_PINMUX_PIN_SLEW_RATE_LIMITED) { + port->PINCFG[i].reg |= PORT_PINCFG_SLEWLIM; + } else { + port->PINCFG[i].reg &= ~PORT_PINCFG_SLEWLIM; + } + } + } +} +#endif + +#ifdef FEATURE_SYSTEM_PINMUX_DRIVE_STRENGTH +/** + * \brief Configures the output driver strength mode for a group of pins. + * + * Configures the output drive strength for a group of pins, to + * control the amount of current the pad is able to sink/source. + * + * \param[in] port Base of the PORT module to configure + * \param[in] mask Mask of the port pin(s) to configure + * \param[in] mode New output driver strength mode to configure + */ +void system_pinmux_group_set_output_strength( + PortGroup *const port, + const uint32_t mask, + const enum system_pinmux_pin_strength mode) +{ + Assert(port); + + for (int i = 0; i < 32; i++) { + if (mask & (1UL << i)) { + if (mode == SYSTEM_PINMUX_PIN_STRENGTH_HIGH) { + port->PINCFG[i].reg |= PORT_PINCFG_DRVSTR; + } else { + port->PINCFG[i].reg &= ~PORT_PINCFG_DRVSTR; + } + } + } +} +#endif + +#ifdef FEATURE_SYSTEM_PINMUX_OPEN_DRAIN +/** + * \brief Configures the output driver mode for a group of pins. + * + * Configures the output driver mode for a group of pins, to + * control the pad behavior. + * + * \param[in] port Base of the PORT module to configure + * \param[in] mask Mask of the port pin(s) to configure + * \param[in] mode New pad output driver mode to configure + */ +void system_pinmux_group_set_output_drive( + PortGroup *const port, + const uint32_t mask, + const enum system_pinmux_pin_drive mode) +{ + Assert(port); + + for (int i = 0; i < 32; i++) { + if (mask & (1UL << i)) { + if (mode == SYSTEM_PINMUX_PIN_DRIVE_OPEN_DRAIN) { + port->PINCFG[i].reg |= PORT_PINCFG_ODRAIN; + } else { + port->PINCFG[i].reg &= ~PORT_PINCFG_ODRAIN; + } + } + } +} +#endif diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/system/pinmux/pinmux.h b/src/boards/mcu/samr34/ASF/sam0/drivers/system/pinmux/pinmux.h new file mode 100644 index 000000000..76e812620 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/system/pinmux/pinmux.h @@ -0,0 +1,669 @@ +/** + * \file + * + * \brief SAM Pin Multiplexer Driver + * + * Copyright (c) 2012-2020 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#ifndef PINMUX_H_INCLUDED +#define PINMUX_H_INCLUDED + +/** + * \defgroup asfdoc_sam0_system_pinmux_group SAM System Pin Multiplexer (SYSTEM PINMUX) Driver + * + * This driver for Atmel® | SMART ARM®-based microcontrollers provides + * an interface for the configuration and management of the device's physical + * I/O Pins, to alter the direction and input/drive characteristics as well as + * to configure the pin peripheral multiplexer selection. + * + * The following peripheral is used by this module: + * - PORT (Port I/O Management) + * + * The following devices can use this module: + * - Atmel | SMART SAM D20/D21 + * - Atmel | SMART SAM R21 + * - Atmel | SMART SAM D09/D10/D11 + * - Atmel | SMART SAM L21/L22 + * - Atmel | SMART SAM DA1 + * - Atmel | SMART SAM C20/C21 + * - Atmel | SMART SAM HA1 + * - Atmel | SMART SAM R30 + * - Atmel | SMART SAM R34 + * - Atmel | SMART SAM R35 + * + * The outline of this documentation is as follows: + * - \ref asfdoc_sam0_system_pinmux_prerequisites + * - \ref asfdoc_sam0_system_pinmux_module_overview + * - \ref asfdoc_sam0_system_pinmux_special_considerations + * - \ref asfdoc_sam0_system_pinmux_extra_info + * - \ref asfdoc_sam0_system_pinmux_examples + * - \ref asfdoc_sam0_system_pinmux_api_overview + * + * + * \section asfdoc_sam0_system_pinmux_prerequisites Prerequisites + * + * There are no prerequisites for this module. + * + * + * \section asfdoc_sam0_system_pinmux_module_overview Module Overview + * + * The SAM devices contain a number of General Purpose I/O pins, used to + * interface the user application logic and internal hardware peripherals to + * an external system. The Pin Multiplexer (PINMUX) driver provides a method + * of configuring the individual pin peripheral multiplexers to select + * alternate pin functions. + * + * \subsection asfdoc_sam0_system_pinmux_features Driver Feature Macro Definition + * + * + * + * + * + * + * + * + * + *
Driver Feature MacroSupported devices
FEATURE_SYSTEM_PINMUX_DRIVE_STRENGTHSAM L21, SAM C20/C21, SAM R34/R35
+ * \note The specific features are only available in the driver when the + * selected device supports those features. + * + * \subsection asfdoc_sam0_system_pinmux_physical_logical_pins Physical and Logical GPIO Pins + * SAM devices use two naming conventions for the I/O pins in the device; one + * physical and one logical. Each physical pin on a device package is assigned + * both a physical port and pin identifier (e.g. "PORTA.0") as well as a + * monotonically incrementing logical GPIO number (e.g. "GPIO0"). While the + * former is used to map physical pins to their physical internal device module + * counterparts, for simplicity the design of this driver uses the logical GPIO + * numbers instead. + * + * \subsection asfdoc_sam0_system_pinmux_peripheral_muxing Peripheral Multiplexing + * SAM devices contain a peripheral MUX, which is individually controllable + * for each I/O pin of the device. The peripheral MUX allows you to select the + * function of a physical package pin - whether it will be controlled as a user + * controllable GPIO pin, or whether it will be connected internally to one of + * several peripheral modules (such as an I2C module). When a pin is + * configured in GPIO mode, other peripherals connected to the same pin will be + * disabled. + * + * \subsection asfdoc_sam0_system_pinmux_pad_characteristics Special Pad Characteristics + * There are several special modes that can be selected on one or more I/O pins + * of the device, which alter the input and output characteristics of the pad. + * + * \subsubsection asfdoc_sam0_system_pinmux_drive_strength Drive Strength + * The Drive Strength configures the strength of the output driver on the + * pad. Normally, there is a fixed current limit that each I/O pin can safely + * drive, however some I/O pads offer a higher drive mode which increases this + * limit for that I/O pin at the expense of an increased power consumption. + * + * \subsubsection asfdoc_sam0_system_pinmux_slew_rate Slew Rate + * The Slew Rate configures the slew rate of the output driver, limiting the + * rate at which the pad output voltage can change with time. + * + * \subsubsection asfdoc_sam0_system_pinmux_input_sample_mode Input Sample Mode + * The Input Sample Mode configures the input sampler buffer of the pad. By + * default, the input buffer is only sampled "on-demand", i.e. when the user + * application attempts to read from the input buffer. This mode is the most + * power efficient, but increases the latency of the input sample by two clock + * cycles of the port clock. To reduce latency, the input sampler can instead + * be configured to always sample the input buffer on each port clock cycle, at + * the expense of an increased power consumption. + * + * \subsection asfdoc_sam0_system_pinmux_module_overview_physical Physical Connection + * + * \ref asfdoc_sam0_system_pinmux_intconnections "The diagram below" shows + * how this module is interconnected within the device: + * + * \anchor asfdoc_sam0_system_pinmux_intconnections + * \dot + * digraph overview { + * node [label="Port Pad" shape=square] pad; + * + * subgraph driver { + * node [label="Peripheral MUX" shape=trapezium] pinmux; + * node [label="GPIO Module" shape=ellipse shape=ellipse style=filled fillcolor=lightgray] gpio; + * node [label="Other Peripheral Modules" shape=ellipse style=filled fillcolor=lightgray] peripherals; + * } + * + * pinmux -> gpio; + * pad -> pinmux; + * pinmux -> peripherals; + * } + * \enddot + * + * \section asfdoc_sam0_system_pinmux_special_considerations Special Considerations + * + * The SAM port pin input sampling mode is set in groups of four physical + * pins; setting the sampling mode of any pin in a sub-group of eight I/O pins + * will configure the sampling mode of the entire sub-group. + * + * High Drive Strength output driver mode is not available on all device pins - + * refer to your device specific datasheet. + * + * + * \section asfdoc_sam0_system_pinmux_extra_info Extra Information + * + * For extra information, see \ref asfdoc_sam0_system_pinmux_extra. This includes: + * - \ref asfdoc_sam0_system_pinmux_extra_acronyms + * - \ref asfdoc_sam0_system_pinmux_extra_dependencies + * - \ref asfdoc_sam0_system_pinmux_extra_errata + * - \ref asfdoc_sam0_system_pinmux_extra_history + * + * + * \section asfdoc_sam0_system_pinmux_examples Examples + * + * For a list of examples related to this driver, see + * \ref asfdoc_sam0_system_pinmux_exqsg. + * + * + * \section asfdoc_sam0_system_pinmux_api_overview API Overview + * @{ + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*@{*/ +#if (SAML21) || (SAMC20) || (SAMC21) || (SAMD21) || (SAMD10) || (SAMD11) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) || defined(__DOXYGEN__) +/** Output Driver Strength Selection feature support */ +# define FEATURE_SYSTEM_PINMUX_DRIVE_STRENGTH +#endif +/*@}*/ + +/** Peripheral multiplexer index to select GPIO mode for a pin */ +#define SYSTEM_PINMUX_GPIO (1 << 7) + +/** + * \brief Port pin direction configuration enum. + * + * Enum for the possible pin direction settings of the port pin configuration + * structure, to indicate the direction the pin should use. + */ +enum system_pinmux_pin_dir { + /** The pin's input buffer should be enabled, so that the pin state can + * be read */ + SYSTEM_PINMUX_PIN_DIR_INPUT, + /** The pin's output buffer should be enabled, so that the pin state can + * be set (but not read back) */ + SYSTEM_PINMUX_PIN_DIR_OUTPUT, + /** The pin's output and input buffers should both be enabled, so that the + * pin state can be set and read back */ + SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK, +}; + +/** + * \brief Port pin input pull configuration enum. + * + * Enum for the possible pin pull settings of the port pin configuration + * structure, to indicate the type of logic level pull the pin should use. + */ +enum system_pinmux_pin_pull { + /** No logical pull should be applied to the pin */ + SYSTEM_PINMUX_PIN_PULL_NONE, + /** Pin should be pulled up when idle */ + SYSTEM_PINMUX_PIN_PULL_UP, + /** Pin should be pulled down when idle */ + SYSTEM_PINMUX_PIN_PULL_DOWN, +}; + +/** + * \brief Port pin digital input sampling mode enum. + * + * Enum for the possible input sampling modes for the port pin configuration + * structure, to indicate the type of sampling a port pin should use. + */ +enum system_pinmux_pin_sample { + /** Pin input buffer should continuously sample the pin state */ + SYSTEM_PINMUX_PIN_SAMPLE_CONTINUOUS, + /** Pin input buffer should be enabled when the IN register is read */ + SYSTEM_PINMUX_PIN_SAMPLE_ONDEMAND, +}; + +/** + * \brief Port pin configuration structure. + * + * Configuration structure for a port pin instance. This structure should + * be initialized by the \ref system_pinmux_get_config_defaults() function + * before being modified by the user application. + */ +struct system_pinmux_config { + /** MUX index of the peripheral that should control the pin, if peripheral + * control is desired. For GPIO use, this should be set to + * \ref SYSTEM_PINMUX_GPIO. */ + uint8_t mux_position; + + /** Port buffer input/output direction */ + enum system_pinmux_pin_dir direction; + + /** Logic level pull of the input buffer */ + enum system_pinmux_pin_pull input_pull; + + /** Enable lowest possible powerstate on the pin + * + * \note All other configurations will be ignored, the pin will be disabled. + */ + bool powersave; +}; + +/** \name Configuration and Initialization + * @{ + */ + +/** + * \brief Initializes a Port pin configuration structure to defaults. + * + * Initializes a given Port pin configuration structure to a set of + * known default values. This function should be called on all new + * instances of these configuration structures before being modified by the + * user application. + * + * The default configuration is as follows: + * \li Non peripheral (i.e. GPIO) controlled + * \li Input mode with internal pull-up enabled + * + * \param[out] config Configuration structure to initialize to default values + */ +static inline void system_pinmux_get_config_defaults( + struct system_pinmux_config *const config) +{ + /* Sanity check arguments */ + Assert(config); + + /* Default configuration values */ + config->mux_position = SYSTEM_PINMUX_GPIO; + config->direction = SYSTEM_PINMUX_PIN_DIR_INPUT; + config->input_pull = SYSTEM_PINMUX_PIN_PULL_UP; + config->powersave = false; +} + +void system_pinmux_pin_set_config( + const uint8_t gpio_pin, + const struct system_pinmux_config *const config); + +void system_pinmux_group_set_config( + PortGroup *const port, + const uint32_t mask, + const struct system_pinmux_config *const config); + +/** @} */ + +/** \name Special Mode Configuration (Physical Group Orientated) + * @{ + */ + +/** + * \brief Retrieves the PORT module group instance from a given GPIO pin number. + * + * Retrieves the PORT module group instance associated with a given logical + * GPIO pin number. + * + * \param[in] gpio_pin Index of the GPIO pin to convert + * + * \return Base address of the associated PORT module. + */ +static inline PortGroup* system_pinmux_get_group_from_gpio_pin( + const uint8_t gpio_pin) +{ + uint8_t port_index = (gpio_pin / 128); + uint8_t group_index = (gpio_pin / 32); + + /* Array of available ports */ + Port *const ports[PORT_INST_NUM] = PORT_INSTS; + + if (port_index < PORT_INST_NUM) { + return &(ports[port_index]->Group[group_index]); + } else { + Assert(false); + return NULL; + } +} + +void system_pinmux_group_set_input_sample_mode( + PortGroup *const port, + const uint32_t mask, + const enum system_pinmux_pin_sample mode); + +/** @} */ + +/** \name Special Mode Configuration (Logical Pin Orientated) + * @{ + */ + +/** + * \brief Retrieves the currently selected MUX position of a logical pin. + * + * Retrieves the selected MUX peripheral on a given logical GPIO pin. + * + * \param[in] gpio_pin Index of the GPIO pin to configure + * + * \return Currently selected peripheral index on the specified pin. + */ +static inline uint8_t system_pinmux_pin_get_mux_position( + const uint8_t gpio_pin) +{ + PortGroup *const port = system_pinmux_get_group_from_gpio_pin(gpio_pin); + uint32_t pin_index = (gpio_pin % 32); + + if (!(port->PINCFG[pin_index].reg & PORT_PINCFG_PMUXEN)) { + return SYSTEM_PINMUX_GPIO; + } + + uint32_t pmux_reg = port->PMUX[pin_index / 2].reg; + + if (pin_index & 1) { + return (pmux_reg & PORT_PMUX_PMUXO_Msk) >> PORT_PMUX_PMUXO_Pos; + } + else { + return (pmux_reg & PORT_PMUX_PMUXE_Msk) >> PORT_PMUX_PMUXE_Pos; + } +} + +/** + * \brief Configures the input sampling mode for a GPIO pin. + * + * Configures the input sampling mode for a GPIO input, to + * control when the physical I/O pin value is sampled and + * stored inside the microcontroller. + * + * \param[in] gpio_pin Index of the GPIO pin to configure + * \param[in] mode New pin sampling mode to configure + */ +static inline void system_pinmux_pin_set_input_sample_mode( + const uint8_t gpio_pin, + const enum system_pinmux_pin_sample mode) +{ + PortGroup* const port = system_pinmux_get_group_from_gpio_pin(gpio_pin); + uint32_t pin_index = (gpio_pin % 32); + + if (mode == SYSTEM_PINMUX_PIN_SAMPLE_ONDEMAND) { + port->CTRL.reg |= (1 << pin_index); + } else { + port->CTRL.reg &= ~(1 << pin_index); + } +} + +/** @} */ + +#ifdef FEATURE_SYSTEM_PINMUX_DRIVE_STRENGTH +/** + * \brief Port pin drive output strength enum. + * + * Enum for the possible output drive strengths for the port pin + * configuration structure, to indicate the driver strength the pin should + * use. + */ +enum system_pinmux_pin_strength { + /** Normal output driver strength */ + SYSTEM_PINMUX_PIN_STRENGTH_NORMAL, + /** High current output driver strength */ + SYSTEM_PINMUX_PIN_STRENGTH_HIGH, +}; + +/** + * \brief Configures the output driver strength mode for a GPIO pin. + * + * Configures the output drive strength for a GPIO output, to + * control the amount of current the pad is able to sink/source. + * + * \param[in] gpio_pin Index of the GPIO pin to configure + * \param[in] mode New output driver strength mode to configure + */ +static inline void system_pinmux_pin_set_output_strength( + const uint8_t gpio_pin, + const enum system_pinmux_pin_strength mode) +{ + PortGroup* const port = system_pinmux_get_group_from_gpio_pin(gpio_pin); + uint32_t pin_index = (gpio_pin % 32); + + if (mode == SYSTEM_PINMUX_PIN_STRENGTH_HIGH) { + port->PINCFG[pin_index].reg |= PORT_PINCFG_DRVSTR; + } + else { + port->PINCFG[pin_index].reg &= ~PORT_PINCFG_DRVSTR; + } +} + +void system_pinmux_group_set_output_strength( + PortGroup *const port, + const uint32_t mask, + const enum system_pinmux_pin_strength mode); +#endif + +#ifdef FEATURE_SYSTEM_PINMUX_SLEWRATE_LIMITER +/** + * \brief Port pin output slew rate enum. + * + * Enum for the possible output drive slew rates for the port pin + * configuration structure, to indicate the driver slew rate the pin should + * use. + */ +enum system_pinmux_pin_slew_rate { + /** Normal pin output slew rate */ + SYSTEM_PINMUX_PIN_SLEW_RATE_NORMAL, + /** Enable slew rate limiter on the pin */ + SYSTEM_PINMUX_PIN_SLEW_RATE_LIMITED, +}; + +/** + * \brief Configures the output slew rate mode for a GPIO pin. + * + * Configures the output slew rate mode for a GPIO output, to + * control the speed at which the physical output pin can react to + * logical changes of the I/O pin value. + * + * \param[in] gpio_pin Index of the GPIO pin to configure + * \param[in] mode New pin slew rate mode to configure + */ +static inline void system_pinmux_pin_set_output_slew_rate( + const uint8_t gpio_pin, + const enum system_pinmux_pin_slew_rate mode) +{ + PortGroup* const port = system_pinmux_get_group_from_gpio_pin(gpio_pin); + uint32_t pin_index = (gpio_pin % 32); + + if (mode == SYSTEM_PINMUX_PIN_SLEW_RATE_LIMITED) { + port->PINCFG[pin_index].reg |= PORT_PINCFG_SLEWLIM; + } + else { + port->PINCFG[pin_index].reg &= ~PORT_PINCFG_SLEWLIM; + } +} + +void system_pinmux_group_set_output_slew_rate( + PortGroup *const port, + const uint32_t mask, + const enum system_pinmux_pin_slew_rate mode); +#endif + +#ifdef FEATURE_SYSTEM_PINMUX_OPEN_DRAIN +/** + * \brief Port pin output drive mode enum. + * + * Enum for the possible output drive modes for the port pin configuration + * structure, to indicate the output mode the pin should use. + */ +enum system_pinmux_pin_drive { + /** Use totem pole output drive mode */ + SYSTEM_PINMUX_PIN_DRIVE_TOTEM, + /** Use open drain output drive mode */ + SYSTEM_PINMUX_PIN_DRIVE_OPEN_DRAIN, +}; + +/** + * \brief Configures the output driver mode for a GPIO pin. + * + * Configures the output driver mode for a GPIO output, to + * control the pad behavior. + * + * \param[in] gpio_pin Index of the GPIO pin to configure + * \param[in] mode New pad output driver mode to configure + */ +static inline void system_pinmux_pin_set_output_drive( + const uint8_t gpio_pin, + const enum system_pinmux_pin_drive mode) +{ + PortGroup* const port = system_pinmux_get_group_from_gpio_pin(gpio_pin); + uint32_t pin_index = (gpio_pin % 32); + + if (mode == SYSTEM_PINMUX_PIN_DRIVE_OPEN_DRAIN) { + port->PINCFG[pin_index].reg |= PORT_PINCFG_ODRAIN; + } + else { + port->PINCFG[pin_index].reg &= ~PORT_PINCFG_ODRAIN; + } +} + +void system_pinmux_group_set_output_drive( + PortGroup *const port, + const uint32_t mask, + const enum system_pinmux_pin_drive mode); +#endif + +#ifdef __cplusplus +} +#endif + +/** @} */ + +/** + * \page asfdoc_sam0_system_pinmux_extra Extra Information for SYSTEM PINMUX Driver + * + * \section asfdoc_sam0_system_pinmux_extra_acronyms Acronyms + * The table below presents the acronyms used in this module: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
AcronymDescription
GPIOGeneral Purpose Input/Output
MUXMultiplexer
+ * + * + * \section asfdoc_sam0_system_pinmux_extra_dependencies Dependencies + * This driver has the following dependencies: + * + * - None + * + * + * \section asfdoc_sam0_system_pinmux_extra_errata Errata + * There are no errata related to this driver. + * + * + * \section asfdoc_sam0_system_pinmux_extra_history Module History + * An overview of the module history is presented in the table below, with + * details on the enhancements and fixes made to the module since its first + * release. The current version of this corresponds to the newest version in + * the table. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Changelog
Removed code of open drain, slew limit and drive strength + * features
Fixed broken sampling mode function implementations, which wrote + * corrupt configuration values to the device registers
Added missing NULL pointer asserts to the PORT driver functions
Initial Release
+ */ + +/** + * \page asfdoc_sam0_system_pinmux_exqsg Examples for SYSTEM PINMUX Driver + * + * This is a list of the available Quick Start guides (QSGs) and example + * applications for \ref asfdoc_sam0_system_pinmux_group. QSGs are simple + * examples with step-by-step instructions to configure and use this driver in a + * selection of use cases. Note that a QSG can be compiled as a standalone + * application or be added to the user application. + * + * - \subpage asfdoc_sam0_system_pinmux_basic_use_case + * + * \page asfdoc_sam0_system_pinmux_document_revision_history Document Revision History + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Doc. Rev. + * Date + * Comments + *
42121F12/2015Added support for SAM L21/L22, SAM DA1, SAM D09, and SAM C20/C21
42121E12/2014Added support for SAM R21 and SAM D10/D11
42121D01/2014Added support for SAM D21
42121C09/2013Fixed incorrect documentation for the device pin sampling mode
42121B06/2013Corrected documentation typos
42121A06/2013Initial release
+ */ + +#endif diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/system/pinmux/quick_start/qs_pinmux_basic.h b/src/boards/mcu/samr34/ASF/sam0/drivers/system/pinmux/quick_start/qs_pinmux_basic.h new file mode 100644 index 000000000..d17aa476e --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/system/pinmux/quick_start/qs_pinmux_basic.h @@ -0,0 +1,86 @@ +/** + * \file + * + * \brief SAM PINMUX Driver Quick Start + * + * Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ + +/** + * \page asfdoc_sam0_system_pinmux_basic_use_case Quick Start Guide for SYSTEM PINMUX - Basic + * + * In this use case, the PINMUX module is configured for: + * \li One pin in input mode, with pull-up enabled, connected to the GPIO + * module + * \li Sampling mode of the pin changed to sample on demand + * + * This use case sets up the PINMUX to configure a physical I/O pin set as + * an input with pull-up and changes the sampling mode of the pin to reduce + * power by only sampling the physical pin state when the user application + * attempts to read it. + * + * \section asfdoc_sam0_system_pinmux_basic_use_case_setup Setup + * + * \subsection asfdoc_sam0_system_pinmux_basic_use_case_setup_prereq Prerequisites + * There are no special setup requirements for this use-case. + * + * \subsection asfdoc_sam0_system_pinmux_basic_use_case_setup_code Code + * Copy-paste the following setup code to your application: + * \snippet qs_pinmux_basic.c setup + * + * \subsection asfdoc_sam0_system_pinmux_basic_use_case_setup_flow Workflow + * -# Create a PINMUX module pin configuration struct, which can be filled out + * to adjust the configuration of a single port pin. + * \snippet qs_pinmux_basic.c pinmux_config + * -# Initialize the pin configuration struct with the module's default values. + * \snippet qs_pinmux_basic.c pinmux_config_defaults + * \note This should always be performed before using the configuration + * struct to ensure that all values are initialized to known default + * settings. + * + * -# Adjust the configuration struct to request an input pin with pull-up + * connected to the GPIO peripheral. + * \snippet qs_pinmux_basic.c pinmux_update_config_values + * -# Configure GPIO10 with the initialized pin configuration struct, to enable + * the input sampler on the pin. + * \snippet qs_pinmux_basic.c pinmux_set_config + * + * \section asfdoc_sam0_system_pinmux_basic_use_case_use_main Use Case + * + * \subsection asfdoc_sam0_system_pinmux_basic_use_case_code Code + * Copy-paste the following code to your user application: + * \snippet qs_pinmux_basic.c main + * + * \subsection asfdoc_sam0_system_pinmux_basic_use_case_flow Workflow + + * -# Adjust the configuration of the pin to enable on-demand sampling mode. + * \snippet qs_pinmux_basic.c pinmux_change_input_sampling + */ +/* + * Support and FAQ: visit Microchip Support + */ diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/system/power/power_sam_l/power.h b/src/boards/mcu/samr34/ASF/sam0/drivers/system/power/power_sam_l/power.h new file mode 100644 index 000000000..fedb4115f --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/system/power/power_sam_l/power.h @@ -0,0 +1,990 @@ +/** + * \file + * + * \brief SAM L21/L22/R30/R34/R35 Power functionality + * + * Copyright (c) 2014-2020 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#ifndef POWER_H_INCLUDED +#define POWER_H_INCLUDED + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup asfdoc_sam0_system_group + * @{ + */ + +/** + * \brief Device sleep modes. + * + * List of available sleep modes in the device. A table of clocks available in + * different sleep modes can be found in \ref asfdoc_sam0_system_module_overview_sleep_mode. + */ +enum system_sleepmode { + /** IDLE sleep mode */ + SYSTEM_SLEEPMODE_IDLE = PM_SLEEPCFG_SLEEPMODE(0x2), + /** STANDBY sleep mode */ + SYSTEM_SLEEPMODE_STANDBY = PM_SLEEPCFG_SLEEPMODE_STANDBY, + /** BACKUP sleep mode */ + SYSTEM_SLEEPMODE_BACKUP = PM_SLEEPCFG_SLEEPMODE_BACKUP, + /** OFF sleep mode */ + SYSTEM_SLEEPMODE_OFF = PM_SLEEPCFG_SLEEPMODE_OFF, +}; + +/** + * \brief Performance level. + * + * List of performance levels. Performance level technique consists of + * adjusting the regulator output voltage to reduce power consumption. + */ +enum system_performance_level { + /** Performance level 0 */ + SYSTEM_PERFORMANCE_LEVEL_0 = PM_PLCFG_PLSEL_PL0, + /** Performance level 2 */ + SYSTEM_PERFORMANCE_LEVEL_2 = PM_PLCFG_PLSEL_PL2, +}; + +/** + * \brief RAM Back-biasing mode. + * + * List of RAM back bias modes. By default, in standby sleep mode, + * RAM is in low power mode (back biased) if its power domain is in + * retention state. This behavior can be changed by configuring the Back Bias + * bit groups in STDBYCFG(STDBYCFG.BBIASxx). + */ +enum system_ram_back_bias_mode { + /** Retention Back biasing mode */ + SYSTEM_RAM_BACK_BIAS_RETENTION = 0, + /** Standby Back Biasing mode */ + SYSTEM_RAM_BACK_BIAS_STANDBY, + /** Standby OFF mode */ + SYSTEM_RAM_BACK_BIAS_STANDBY_OFF, + /** Always OFF mode */ + SYSTEM_RAM_BACK_BIAS_OFF, +}; + +#if SAML21 || SAMR30 || (SAMR34) || (SAMR35)|| (WLR089) +/** + * \brief Linked power domain. + * + * List of linked power domains. Power domains can be linked to each other. + * It allows a power domain (PDn) to be kept in active state if the inferior + * power domain (PDn-1) is in active state too. + */ +enum system_linked_power_domain { + /** Power domains PD0/PD1/PD2 are not linked */ + SYSTEM_LINKED_POWER_DOMAIN_DEFAULT = PM_STDBYCFG_LINKPD_DEFAULT_Val, + /** Power domains PD0 and PD1 are linked */ + SYSTEM_LINKED_POWER_DOMAIN_PD01 = PM_STDBYCFG_LINKPD_PD01_Val, + /** Power domains PD1 and PD2 are linked */ + SYSTEM_LINKED_POWER_DOMAIN_PD12 = PM_STDBYCFG_LINKPD_PD12_Val, + /** All Power domains are linked */ + SYSTEM_LINKED_POWER_DOMAIN_PD012 = PM_STDBYCFG_LINKPD_PD012_Val, +}; + +#if (SAML21XXXB) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) +/** + * \brief VREG switching mode. + * + * List of VREG switching modes. + */ +enum system_vreg_switch_mode { + /** Automatic mode. */ + SYSTEM_SYSTEM_VREG_SWITCH_AUTO = 0, + /** Performance oriented. */ + SYSTEM_SYSTEM_VREG_SWITCH_PERFORMANCE, + /** Low Power consumption oriented. */ + SYSTEM_SYSTEM_VREG_SWITCH_LP, +}; +#endif + +/** + * \brief Power domain. + * + * List of power domains. Power domain gating technique consists of turning + * on or off power domain voltage to save power while keeping other domains + * powered up. + */ +enum system_power_domain { + /** All power domains switching are handled by hardware */ + SYSTEM_POWER_DOMAIN_DEFAULT = PM_STDBYCFG_PDCFG_DEFAULT_Val, + /** Power domain 0 (PD0) is forced ACTIVE */ + SYSTEM_POWER_DOMAIN_PD0 = PM_STDBYCFG_PDCFG_PD0_Val, + /** Power domain 0 and 1 (PD0 and PD1) are forced ACTIVE */ + SYSTEM_POWER_DOMAIN_PD01 = PM_STDBYCFG_PDCFG_PD01_Val, + /** All power domains are forced ACTIVE */ + SYSTEM_POWER_DOMAIN_PD012 = PM_STDBYCFG_PDCFG_PD012_Val, +}; +#endif + +#if SAML22 +/** + * \brief Voltage Regulator switch in Standby mode. + * + */ +enum system_vreg_switch_mode { + /** Automatic mode. */ + SYSTEM_VREG_SWITCH_AUTO = PM_STDBYCFG_VREGSMOD_AUTO_Val, + /** Performance oriented. */ + SYSTEM_VREG_SWITCH_PERFORMANCE = PM_STDBYCFG_VREGSMOD_PERFORMANCE_Val, + /** Low Power consumption oriented. */ + SYSTEM_VREG_SWITCH_LP = PM_STDBYCFG_VREGSMOD_LP_Val, +}; + +#endif + +/** + * \brief Voltage regulator. + * + * Voltage regulators selection. In active mode, the voltage regulator + * can be chosen on the fly between a LDO or a Buck converter. + */ +enum system_voltage_regulator_sel { + /** The voltage regulator in active mode is a LDO voltage regulator */ + SYSTEM_VOLTAGE_REGULATOR_LDO = SUPC_VREG_SEL_LDO_Val, + /** The voltage regulator in active mode is a buck converter */ + SYSTEM_VOLTAGE_REGULATOR_BUCK = SUPC_VREG_SEL_BUCK_Val, +}; + +/** + * \brief Low power efficiency. + * + * Low power mode efficiency. + */ +enum system_voltage_regulator_low_power_efficiency { + /** The voltage regulator in Low power mode has the default efficiency and + support the whole VDD range (1.62V to 3.6V) */ + SYSTEM_VOLTAGE_REGULATOR_LOW_POWER_EFFICIENCY_DEFAULT, + /** The voltage regulator in Low power mode has the highest efficiency and + support the limited VDD range (2.5V to 3.6V) */ + SYSTEM_VOLTAGE_REGULATOR_LOW_POWER_EFFICIENCY_HIGHTEST, +}; + +/** + * \brief Voltage reference value. + * + * Voltage references selection. + */ +enum system_voltage_references_sel { + /** 1.0V voltage reference typical value */ + SYSTEM_VOLTAGE_REFERENCE_1V0 = SUPC_VREF_SEL_1V0_Val, + /** 1.1V voltage reference typical value */ + SYSTEM_VOLTAGE_REFERENCE_1V1 = SUPC_VREF_SEL_1V1_Val, + /** 1.2V voltage reference typical value */ + SYSTEM_VOLTAGE_REFERENCE_1V2 = SUPC_VREF_SEL_1V2_Val, + /** 1.25V voltage reference typical value */ + SYSTEM_VOLTAGE_REFERENCE_1V25 = SUPC_VREF_SEL_1V25_Val, + /** 2.0V voltage reference typical value */ + SYSTEM_VOLTAGE_REFERENCE_2V0 = SUPC_VREF_SEL_2V0_Val, + /** 2.2V voltage reference typical value */ + SYSTEM_VOLTAGE_REFERENCE_2V2 = SUPC_VREF_SEL_2V2_Val, + /** 2.4V voltage reference typical value */ + SYSTEM_VOLTAGE_REFERENCE_2V4 = SUPC_VREF_SEL_2V4_Val, + /** 2.5V voltage reference typical value */ + SYSTEM_VOLTAGE_REFERENCE_2V5 = SUPC_VREF_SEL_2V5_Val, +}; + +/** + * \brief Battery power switch configuration enum. + * + * Enum for Battery power switch modes. + */ +enum system_battery_power_switch { + /** The backup domain is always supplied by main power */ + SYSTEM_BATTERY_POWER_SWITCH_NONE = SUPC_BBPS_CONF_NONE_Val, + /** The power switch is handled by the automatic power switch */ + SYSTEM_BATTERY_POWER_SWITCH_AUTOMATIC = SUPC_BBPS_CONF_APWS_Val, + /** The backup domain is always supplied by battery backup power */ + SYSTEM_BATTERY_POWER_SWITCH_FORCED = SUPC_BBPS_CONF_FORCED_Val, + /** The power switch is handled by the BOD33 */ + SYSTEM_BATTERY_POWER_SWITCH_BOD33 = SUPC_BBPS_CONF_BOD33_Val, +}; + +/** + * \brief Voltage reference. + * + * List of available voltage references (VREF) that may be used within the + * device. + */ +enum system_voltage_reference { + /** Temperature sensor voltage reference */ + SYSTEM_VOLTAGE_REFERENCE_TEMPSENSE, + /** Voltage reference output */ + SYSTEM_VOLTAGE_REFERENCE_OUTPUT, +}; + +/** + * \brief Backup IO enum. + * + * List of Backup input and output pins. + * If enabled (\ref system_backup_pin_output_enable), the pins can be driven + * by the SUPC. + */ +enum system_backup_pin { + /** Power Supply OK status pin */ + SYSTEM_BACKUP_PIN_PSOK = (0x1 << 0), + /** Backup output pin 0 */ + SYSTEM_BACKUP_PIN_OUT_0 = (0x1 << 1), + /** Backup output pin 1 */ + SYSTEM_BACKUP_PIN_OUT_1 = (0x1 << 2) +}; + +/** + * \brief Standby configuration. + * + * Configuration structure for standby mode. + */ +struct system_standby_config { +#if SAML21 || SAMR30 || (SAMR34) || (SAMR35) || (WLR089) + /** Power domain. */ + enum system_power_domain power_domain; + /** Enable dynamic power gating for power domain 0 */ + bool enable_dpgpd0; + /** Enable dynamic power gating for power domain 1 */ + bool enable_dpgpd1; +#if (SAML21XXXA) + /** Automatic VREG switching disable. */ + bool disable_avregsd; +#else + /** VREG switching mode */ + enum system_vreg_switch_mode vregs_mode; +#endif + /** Linked power domain */ + enum system_linked_power_domain linked_power_domain; +#elif SAML22 + /** Regulator switch mode in standby. */ + enum system_vreg_switch_mode vreg_switch_mode; +#endif + /** Back bias for HMCRAMCHS. */ + enum system_ram_back_bias_mode hmcramchs_back_bias; + /** Back bias for HMCRAMCLP */ + enum system_ram_back_bias_mode hmcramclp_back_bias; +}; + +/** + * \brief Voltage Regulator System (VREG) Control configuration. + * + * Configuration structure for VREG. + */ +struct system_voltage_regulator_config { + /** Voltage scaling period */ + uint8_t voltage_scale_period; + /** Voltage scaling voltage step */ + uint8_t voltage_scale_step; + /** Run in standby in standby sleep mode */ + bool run_in_standby; + /** Voltage Regulator Selection */ + enum system_voltage_regulator_sel regulator_sel; + /** Low power efficiency */ + enum system_voltage_regulator_low_power_efficiency low_power_efficiency; +#if SAML22 || SAML21XXXB || (SAMR34J) || (SAMR35J) || (WLR089U0) + /** Run in standby in performance level 0. */ + bool run_in_standby_pl0; +#endif +}; + +/** + * \brief Voltage References System (VREF) Control configuration. + * + * Configuration structure for VREF. + */ +struct system_voltage_references_config { + /** Voltage References Selection */ + enum system_voltage_references_sel sel; + /** On Demand Control */ + bool on_demand; + /** Run in standby */ + bool run_in_standby; +#if SAML22 + /** Temperature Sensor Selection. */ + bool temperature_sensor_sel; +#endif +}; + +/** + * \brief Battery Backup Power Switch (BBPS) Control configuration. + * + * Configuration structure for Battery Backup Power Switch (BBPS). + */ +struct system_battery_backup_power_switch_config { + /** Enable device wake up when BBPS switches from + battery backup power to main power */ + bool wake_enabled; + /** Battery backup power switch configuration */ + enum system_battery_power_switch battery_power_switch; +}; + +/** + * \name Voltage Regulator + * @{ + */ + +/** + * \brief Retrieve the default configuration for voltage regulator. + * + * Fills a configuration structure with the default configuration: + * - Voltage scaling period is 1μs + * - Voltage scaling voltage step is 2*min_step + * - The voltage regulator is in low power mode in Standby sleep mode + * - The voltage regulator in active mode is an LDO voltage regulator + * - The voltage regulator in Low power mode has the default efficiency + * + * \param[out] config Configuration structure to fill with default values + */ +static inline void system_voltage_regulator_get_config_defaults( + struct system_voltage_regulator_config *const config) +{ + Assert(config); + config->voltage_scale_period = 0; + config->voltage_scale_step = 0; + config->run_in_standby = false; + config->regulator_sel = SYSTEM_VOLTAGE_REGULATOR_LDO; + config->low_power_efficiency = SYSTEM_VOLTAGE_REGULATOR_LOW_POWER_EFFICIENCY_DEFAULT; +#if SAML22 || SAML21XXXB || SAMR34J || SAMR35J || (WLR089U0) + config->run_in_standby_pl0 = false; +#endif +} + +/** + * \brief Configure voltage regulator. + * + * Configures voltage regulator with the given configuration. + * + * \param[in] config Voltage regulator configuration structure containing + * the new config + */ +static inline void system_voltage_regulator_set_config( + struct system_voltage_regulator_config *const config) +{ + Assert(config); + SUPC->VREG.bit.VSPER = config->voltage_scale_period; + SUPC->VREG.bit.VSVSTEP = config->voltage_scale_step; + SUPC->VREG.bit.RUNSTDBY = config->run_in_standby; + SUPC->VREG.bit.SEL = config->regulator_sel; +#if (SAML21XXXB) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + SUPC->VREG.bit.LPEFF = config->low_power_efficiency; +#endif +#if SAML22 || SAML21XXXB || SAMR34J || SAMR35J || (WLR089U0) + SUPC->VREG.bit.STDBYPL0 = config->run_in_standby_pl0; +#endif + while(!(SUPC->STATUS.reg & SUPC_STATUS_VREGRDY)) { + ; + } +} + +/** +* \brief Enable the selected voltage regulator. + * + * Enables the selected voltage regulator source. + */ +static inline void system_voltage_regulator_enable(void) +{ + SUPC->VREG.reg |= SUPC_VREG_ENABLE; +} + +/** + * \brief Disable the selected voltage regulator. + * + * Disables the selected voltage regulator. + */ +static inline void system_voltage_regulator_disable(void) +{ + SUPC->VREG.reg &= ~SUPC_VREG_ENABLE; +} + +/** + * @} + */ + +/** + * \name Voltage References + * @{ + */ + +/** + * \brief Retrieve the default configuration for voltage reference. + * + * Fill a configuration structure with the default configuration: + * - 1.0V voltage reference typical value + * - On demand control disabled + * - The voltage reference and the temperature sensor are halted during standby sleep mode + * + * \param[out] config Configuration structure to fill with default values + */ +static inline void system_voltage_reference_get_config_defaults( + struct system_voltage_references_config *const config) +{ + Assert(config); + config->sel = SYSTEM_VOLTAGE_REFERENCE_1V0; + config->on_demand = false; + config->run_in_standby = false; +#if SAML22 + config->temperature_sensor_sel = false; +#endif +} + +/** + * \brief Configure voltage reference. + * + * Configures voltage reference with the given configuration. + * + * \param[in] config Voltage reference configuration structure containing + * the new config + */ +static inline void system_voltage_reference_set_config( + struct system_voltage_references_config *const config) +{ + Assert(config); + SUPC->VREF.bit.SEL = config->sel; + SUPC->VREF.bit.ONDEMAND = config->on_demand; + SUPC->VREF.bit.RUNSTDBY = config->run_in_standby; +#if SAML22 + SUPC->VREF.bit.TSSEL = config->temperature_sensor_sel; +#endif +} + +/** + * \brief Enable the selected voltage reference. + * + * Enables the selected voltage reference source, making the voltage reference + * available on a pin as well as an input source to the analog peripherals. + * + * \param[in] vref Voltage reference to enable + */ +static inline void system_voltage_reference_enable( + const enum system_voltage_reference vref) +{ + switch (vref) { + case SYSTEM_VOLTAGE_REFERENCE_TEMPSENSE: + SUPC->VREF.reg |= SUPC_VREF_TSEN; + break; + case SYSTEM_VOLTAGE_REFERENCE_OUTPUT: + SUPC->VREF.reg |= SUPC_VREF_VREFOE; + break; + default: + Assert(false); + return; + } +} + +/** + * \brief Disable the selected voltage reference. + * + * Disables the selected voltage reference source. + * + * \param[in] vref Voltage reference to disable + */ +static inline void system_voltage_reference_disable( + const enum system_voltage_reference vref) +{ + switch (vref) { + case SYSTEM_VOLTAGE_REFERENCE_TEMPSENSE: + SUPC->VREF.reg &= ~SUPC_VREF_TSEN; + break; + case SYSTEM_VOLTAGE_REFERENCE_OUTPUT: + SUPC->VREF.reg &= ~SUPC_VREF_VREFOE; + break; + default: + Assert(false); + return; + } +} + +/** + * @} + */ + +/** + * \name Battery Backup Power Switch + * @{ + */ + +/** + * \brief Retrieve the default configuration for battery backup power switch control. + * + * Fills a configuration structure with the default configuration: + * - The main Power Supply OK status is not available on the PSOK pin + * - The device is not woken up when switched from battery backup power to main power + * - The backup domain is always supplied by main power + * + * \param[out] config Configuration structure to fill with default values + */ +static inline void system_battery_backup_power_switch_get_config_defaults( + struct system_battery_backup_power_switch_config *const config) +{ + Assert(config); + config->wake_enabled = false; + config->battery_power_switch = SYSTEM_BATTERY_POWER_SWITCH_NONE; +} + +/** + * \brief Configure battery backup power switch. + * + * Configures battery backup power switch with the given configuration. + * + * \param[in] config Battery backup power switch configuration structure containing + * the new config + */ +static inline void system_battery_backup_power_switch_set_config( + struct system_battery_backup_power_switch_config *const config) +{ + Assert(config); + uint32_t new_config = SUPC->BBPS.reg & SUPC_BBPS_PSOKEN; + + if(config->wake_enabled) { + new_config |= SUPC_BBPS_WAKEEN; + } + + new_config |= SUPC_BBPS_CONF(config->battery_power_switch); + + SUPC->BBPS.reg = new_config; + + if (config->battery_power_switch == SYSTEM_BATTERY_POWER_SWITCH_AUTOMATIC) { + while (!(SUPC->STATUS.reg & SUPC_STATUS_APWSRDY)) { + ; + } + } +} + +/** + * @} + */ + +/** + * \name Output Pins in Backup Mode + * @{ + */ + +/** + * \brief Enable the backup pin output. + * + * The output is enabled and driven by the SUPC. + * + * \param[in] pin Backup pin index + */ +static inline void system_backup_pin_output_enable( + enum system_backup_pin pin) +{ + if (pin == SYSTEM_BACKUP_PIN_PSOK) { + SUPC->BBPS.reg |= SUPC_BBPS_PSOKEN; + } else { + SUPC->BKOUT.reg |= SUPC_BKOUT_EN(pin >> 1); + } +} + +/** + * \brief Disable the backup pin output. + * + * The output is not enabled. + * + * \param[in] pin Backup pin index + */ +static inline void system_backup_pin_output_disable( + enum system_backup_pin pin) +{ + if (pin == SYSTEM_BACKUP_PIN_PSOK) { + SUPC->BBPS.reg &= ~SUPC_BBPS_PSOKEN; + } else { + SUPC->BKOUT.reg &= ~SUPC_BKOUT_EN(pin >> 1); + } +} + +/** + * \brief Check if backup pin output is enabled. + * + * \param[in] pin Backup pin index + * + * \return The enabled status. + * \retval true The output is enabled + * \retval false The output is not enabled + */ +static inline bool system_backup_pin_output_is_enabled( + enum system_backup_pin pin) +{ + bool enabled = false; + + if (pin == SYSTEM_BACKUP_PIN_PSOK) { + if (SUPC->BBPS.reg & SUPC_BBPS_PSOKEN) { + enabled = true; + } + } else { + if (SUPC->BKOUT.reg & SUPC_BKOUT_EN(pin >> 1)) { + enabled = true; + } + } + return enabled; +} + +/** + * \brief Enable the backup pin toggle on RTC event. + * + * Toggle output on RTC event is enabled. + * + * \param[in] pin Backup pin index + */ +static inline void system_backup_pin_output_enable_rtc_toggle( + enum system_backup_pin pin) +{ + Assert(pin != SYSTEM_BACKUP_PIN_PSOK); + + SUPC->BKOUT.reg |= SUPC_BKOUT_RTCTGL(pin >> 1); +} + +/** + * \brief Disable the backup pin toggle on RTC event. + * + * Toggle output on RTC event is disabled. + * + * \param[in] pin Backup pin index + */ +static inline void system_backup_pin_output_disable_rtc_toggle( + enum system_backup_pin pin) +{ + Assert(pin != SYSTEM_BACKUP_PIN_PSOK); + + SUPC->BKOUT.reg &= ~SUPC_BKOUT_RTCTGL(pin >> 1); +} + +/** + * \brief Set the backup pin. + * + * Set the corresponding output pin. + * + * \param[in] pin Backup pin index + */ +static inline void system_backup_pin_output_set( + enum system_backup_pin pin) +{ + Assert(pin != SYSTEM_BACKUP_PIN_PSOK); + + SUPC->BKOUT.reg |= SUPC_BKOUT_SET(pin >> 1); +} + +/** + * \brief Clear the backup pin. + * + * Clear the corresponding output. + * + * \param[in] pin Backup pin index + */ +static inline void system_backup_pin_output_clear( + enum system_backup_pin pin) +{ + Assert(pin != SYSTEM_BACKUP_PIN_PSOK); + + SUPC->BKOUT.reg |= SUPC_BKOUT_CLR(pin >> 1); +} + +/** + * \brief Get the backup I/O input values. + * + * Get the backup I/O data input values. If the corresponding pin is enabled, + * the I/O input value is given on the pin. + * + * \param[in] pin Backup pin index + * + * \return The backup I/O input level value. + */ +static inline bool system_backup_pin_output_get(enum system_backup_pin pin) +{ + Assert(pin != SYSTEM_BACKUP_PIN_PSOK); + + return (SUPC->BKIN.reg & SUPC_BKIN_BKIN(pin >> 1)); +} + +/** + * @} + */ + +/** + * \name Device Sleep Control + * @{ + */ + +/** + * \brief Set the sleep mode of the device. + * + * Sets the sleep mode of the device; the configured sleep mode will be entered + * upon the next call of the \ref system_sleep() function. + * + * For an overview of which systems are disabled in sleep for the different + * sleep modes, see \ref asfdoc_sam0_system_module_overview_sleep_mode. + * + * \param[in] sleep_mode Sleep mode to configure for the next sleep operation + */ +static inline void system_set_sleepmode( + const enum system_sleepmode sleep_mode) +{ + PM->SLEEPCFG.reg = sleep_mode; + while(PM->SLEEPCFG.reg != sleep_mode) ; +} + +/** + * \brief Put the system to sleep waiting for interrupt. + * + * Executes a device DSB (Data Synchronization Barrier) instruction to ensure + * all ongoing memory accesses have completed. Further, a WFI (Wait For Interrupt) + * instruction is executed to place the device into the sleep mode specified by + * \ref system_set_sleepmode. + */ +static inline void system_sleep(void) +{ + __DSB(); + __WFI(); +} + +/** + * @} + */ + +/** + * \name Performance Level Control + * @{ + */ + +/** + * \brief Switch performance level. + * + * The bus frequency must be reduced prior to scaling down the performance level, + * in order to not exceed the maximum frequency allowed for the performance level. + * + * When scaling up the performance level (for example from PL0 to PL2), the bus + * frequency can be increased first when the performance level transition is + * completed. Check the performance level status before increasing the frequency. + * + * \param[in] performance_level Performance level to switch + * + * \retval STATUS_ERR_INVALID_ARG Invalid parameter + * \retval STATUS_OK Successfully + */ +static inline enum status_code system_switch_performance_level( + const enum system_performance_level performance_level) +{ + + if (performance_level == (enum system_performance_level)PM->PLCFG.reg) { + return STATUS_OK; + } + +#if SAML22 || SAML21XXXB || SAMR34J || SAMR35J || (WLR089U0) + if (PM->PLCFG.reg & PM_PLCFG_PLDIS) { + return STATUS_ERR_INVALID_ARG; + } +#endif + + /* Clear performance level status */ + PM->INTFLAG.reg = PM_INTFLAG_PLRDY; + + /* Switch performance level */ + PM->PLCFG.reg = performance_level; + + /* Waiting performance level ready */ + while (!PM->INTFLAG.reg) { + ; + } + return STATUS_OK; +} + +#if SAML22 || SAML21XXXB || SAMR34J || SAMR35J || (WLR089U0) +/** + * \brief Enable performance level switch. + * + * Enable performance level switch. + */ +static inline void system_performance_level_enable(void) +{ + PM->PLCFG.reg &= ~PM_PLCFG_PLDIS; +} + +/** + * \brief Disable performance level switch. + * + * Disable performance level switch. + */ +static inline void system_performance_level_disable(void) +{ + PM->PLCFG.reg |= PM_PLCFG_PLDIS; +} +#endif + +/** + * \brief Get performance level. + * + * Get performance level. + * + * \return Current performance level. + */ +static inline enum system_performance_level system_get_performance_level(void) +{ + return (enum system_performance_level)PM->PLCFG.reg; +} + +/** + * \brief Get performance level status. + * + * Get performance level status. + * \return Performance level status: Written to one when the performance level is ready. + */ +static inline uint8_t system_get_performance_level_status(void) +{ + return PM->INTFLAG.reg; +} + +/** + * \brief Clear performance level status. + * + * Clear performance level status. + */ +static inline void system_clear_performance_level_status(void) +{ + PM->INTFLAG.reg = PM_INTFLAG_PLRDY; +} + +/** + * @} + */ + +/** + * \name Standby Configuration + * @{ + */ + +/** + * \brief Retrieve the default configuration for standby. + * + * Fills a configuration structure with the default configuration for standby: + * - Retention back biasing mode for HMCRAMCLP + * - Retention back biasing mode for HMCRAMCHS + * - Power domains PD0/PD1/PD2 are not linked + * - Automatic VREG switching is used + * - Dynamic power gating for power domain 1 is disabled + * - Dynamic power gating for power domain 0 is disabled + * - All power domains switching are handled by hardware + * + * \param[out] config Configuration structure to fill with default values + */ +static inline void system_standby_get_config_defaults( + struct system_standby_config *const config) +{ + Assert(config); +#if SAML21 || SAMR30 || (SAMR34) || (SAMR35) || (WLR089) + config->power_domain = SYSTEM_POWER_DOMAIN_DEFAULT; + config->enable_dpgpd0 = false; + config->enable_dpgpd1 = false; +#if (SAML21XXXB) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + config->vregs_mode = SYSTEM_SYSTEM_VREG_SWITCH_AUTO; +#else + config->disable_avregsd = false; +#endif + config->linked_power_domain = SYSTEM_LINKED_POWER_DOMAIN_DEFAULT; +#elif SAML22 + config->vreg_switch_mode = SYSTEM_VREG_SWITCH_AUTO; +#endif + config->hmcramchs_back_bias = SYSTEM_RAM_BACK_BIAS_RETENTION; + config->hmcramclp_back_bias = SYSTEM_RAM_BACK_BIAS_RETENTION; +} + +/** + * \brief Configure standby mode. + * + * Configures standby with the given configuration. + * + * \param[in] config Standby configuration structure containing + * the new config + */ +static inline void system_standby_set_config( + struct system_standby_config *const config) +{ + Assert(config); +#if SAML21 || SAMR30 || (SAMR34) || (SAMR35) || (WLR089) + PM->STDBYCFG.reg = PM_STDBYCFG_PDCFG(config->power_domain) + | (config->enable_dpgpd0 << PM_STDBYCFG_DPGPD0_Pos) + | (config->enable_dpgpd1 << PM_STDBYCFG_DPGPD1_Pos) +#if (SAML21XXXB) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + | PM_STDBYCFG_VREGSMOD(config->vregs_mode) +#else + | (config->disable_avregsd << PM_STDBYCFG_AVREGSD_Pos) +#endif + | PM_STDBYCFG_LINKPD(config->linked_power_domain) + | PM_STDBYCFG_BBIASHS(config->hmcramchs_back_bias) + | PM_STDBYCFG_BBIASLP(config->hmcramclp_back_bias); +#elif SAML22 + PM->STDBYCFG.reg = PM_STDBYCFG_VREGSMOD(config->vreg_switch_mode) | + PM_STDBYCFG_BBIASHS(config->hmcramchs_back_bias); +#endif +} + +/** + * @} + */ + +/** + * \name I/O Retention + * @{ + */ + +/** + * \brief Enable I/O retention. + * + * Enable I/O retention. After waking up from Backup mode, I/O lines are held + * until the bit is written to 0. + */ +static inline void system_io_retension_enable(void) +{ + PM->CTRLA.reg = PM_CTRLA_IORET; +} + +/** + * \brief Disable I/O retention. + * + * Disable IO retention. After waking up from Backup mode, I/O lines are not held. + */ +static inline void system_io_retension_disable(void) +{ + PM->CTRLA.reg = PM_CTRLA_MASK & (~PM_CTRLA_IORET); +} + +/** + * @} + */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* POWER_H_INCLUDED */ diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/system/reset/reset_sam_l/reset.h b/src/boards/mcu/samr34/ASF/sam0/drivers/system/reset/reset_sam_l/reset.h new file mode 100644 index 000000000..1d8295a7c --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/system/reset/reset_sam_l/reset.h @@ -0,0 +1,255 @@ +/** + * \file + * + * \brief SAM Reset functionality + * + * Copyright (c) 2014-2020 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#ifndef RESET_H_INCLUDED +#define RESET_H_INCLUDED + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup asfdoc_sam0_system_group + * @{ + */ + +/** + * \brief Reset causes of the system. + * + * List of possible reset causes of the system. + */ +enum system_reset_cause { + /** The system was last reset by a backup reset */ + SYSTEM_RESET_CAUSE_BACKUP = RSTC_RCAUSE_BACKUP, + /** The system was last reset by a software reset */ + SYSTEM_RESET_CAUSE_SOFTWARE = RSTC_RCAUSE_SYST, + /** The system was last reset by the watchdog timer */ + SYSTEM_RESET_CAUSE_WDT = RSTC_RCAUSE_WDT, + /** The system was last reset because the external reset line was pulled low */ + SYSTEM_RESET_CAUSE_EXTERNAL_RESET = RSTC_RCAUSE_EXT, +#if SAML21 || SAMR30 || (SAMR34) || (SAMR35) || (WLR089) + /** The system was last reset by the BOD33. */ + SYSTEM_RESET_CAUSE_BOD33 = RSTC_RCAUSE_BOD33, + /** The system was last reset by the BOD12 */ + SYSTEM_RESET_CAUSE_BOD12 = RSTC_RCAUSE_BOD12, +#else + /** The system was last reset by the BOD VDD. */ + SYSTEM_RESET_CAUSE_BOD33 = RSTC_RCAUSE_BODVDD, + /** The system was last reset by the BOD CORE. */ + SYSTEM_RESET_CAUSE_BOD12 = RSTC_RCAUSE_BODCORE, +#endif + /** The system was last reset by the POR (Power on reset). */ + SYSTEM_RESET_CAUSE_POR = RSTC_RCAUSE_POR, +}; + +/** + * \brief Backup exit source after a backup reset occurs. + * + * List of possible backup exit source. + */ +enum system_reset_backup_exit_source { +#if SAML21 || SAMR30 || (SAMR34) || (SAMR35) || (WLR089) + /** The backup exit source was external wakeup. */ + SYSTEM_RESET_BACKKUP_EXIT_EXTWAKE = RSTC_BKUPEXIT_EXTWAKE, +#endif + /** The backup exit source was RTC interrupt. */ + SYSTEM_RESET_BACKKUP_EXIT_RTC = RSTC_BKUPEXIT_RTC, + /** The backup exit source was battery backup power switch */ + SYSTEM_RESET_BACKKUP_EXIT_BBPS = RSTC_BKUPEXIT_BBPS, +}; + +#if SAML21 || SAMR30 || (SAMR34) || (SAMR35) || (WLR089) +/** + * \brief Wakeup debounce counter value. + * + * Wakeup debounce counter value when waking up by external wakeup pin from backup mode. + */ +enum system_wakeup_debounce_count { + /** No debouncing */ + SYSTEM_WAKEUP_DEBOUNCE_OFF = RSTC_WKDBCONF_WKDBCNT_OFF, + /** Input pin shall be active for at least two 32KHz clock period. */ + SYSTEM_WAKEUP_DEBOUNCE_2CK32 = RSTC_WKDBCONF_WKDBCNT_2CK32, + /** Input pin shall be active for at least three 32KHz clock period. */ + SYSTEM_WAKEUP_DEBOUNCE_3CK32 = RSTC_WKDBCONF_WKDBCNT_3CK32, + /** Input pin shall be active for at least 32 32KHz clock periods */ + SYSTEM_WAKEUP_DEBOUNCE_32CK32 = RSTC_WKDBCONF_WKDBCNT_32CK32, + /** Input pin shall be active for at least 512 32KHz clock periods */ + SYSTEM_WAKEUP_DEBOUNCE_512CK32 = RSTC_WKDBCONF_WKDBCNT_512CK32, + /** Input pin shall be active for at least 4096 32KHz clock periods */ + SYSTEM_WAKEUP_DEBOUNCE_4096CK32 = RSTC_WKDBCONF_WKDBCNT_4096CK32, + /** Input pin shall be active for at least 32768 32KHz clock periods */ + SYSTEM_WAKEUP_DEBOUNCE_32768CK32 = RSTC_WKDBCONF_WKDBCNT_32768CK32, +}; +#endif + +/** + * \name Reset Control + * @{ + */ + +/** + * \brief Reset the MCU. + * + * Resets the MCU and all associated peripherals and registers, except RTC, + * OSC32KCTRL, RSTC, GCLK (if WRTLOCK is set), and I/O retention state of PM. + * + */ +static inline void system_reset(void) +{ + NVIC_SystemReset(); +} + +/** + * \brief Get the reset cause. + * + * Retrieves the cause of the last system reset. + * + * \return An enum value indicating the cause of the last system reset. + */ +static inline enum system_reset_cause system_get_reset_cause(void) +{ + return (enum system_reset_cause)RSTC->RCAUSE.reg; +} + +/** + * @} + */ + +/** + * \name Backup Exit Control + * @{ + */ + +/** + * \brief Get the backup exit source. + * + * Get the backup exit source when a backup reset occurs. + * + * \return An enum value indicating the latest backup exit source. + */ +static inline enum system_reset_backup_exit_source system_get_backup_exit_source(void) +{ + return (enum system_reset_backup_exit_source)RSTC->BKUPEXIT.reg; +} + +#if SAML21 || SAMR30 || (SAMR34) || (SAMR35) || (WLR089) +/** + * \brief Set wakeup debounce counter. + * + * Set the wakeup debounce counter value with the given count. + * + * \param[in] wakeup_debounce_count Wakeup debounce counter value + */ +static inline void system_set_pin_wakeup_debounce_counter( + const enum system_wakeup_debounce_count wakeup_debounce_count) +{ + RSTC->WKDBCONF.reg = wakeup_debounce_count; +} + +/** + * \brief Set low polarity of wakeup input pin. + * + * Set low polarity with the given wakeup input pin mask. + * + * \param[in] pin_mask Input pin mask + */ +static inline void system_set_pin_wakeup_polarity_low(const uint16_t pin_mask) +{ + RSTC->WKPOL.reg &= ~(RSTC_WKPOL_WKPOL(pin_mask)); +} + +/** + * \brief Set high polarity of wakeup input pin. + * + * Set high polarity with the given wakeup input pin mask. + * + * \param[in] pin_mask Input pin mask + */ +static inline void system_set_pin_wakeup_polarity_high(const uint16_t pin_mask) +{ + RSTC->WKPOL.reg |= RSTC_WKPOL_WKPOL(pin_mask); +} + +/** + * \brief Enable wakeup of input pin from the backup mode. + * + * Enable pin wakeup from the backup mode with the given pin mask. + * + * \param[in] pin Input pin mask + */ +static inline void system_enable_pin_wakeup(const uint16_t pin_mask) +{ + RSTC->WKEN.reg |= RSTC_WKEN_WKEN(pin_mask); +} + +/** + * \brief Disable wakeup of input pin from the backup mode. + * + * Disable pin wakeup from the backup mode with the given pin mask. + * + * \param[in] pin Input pin mask + */ +static inline void system_disable_pin_wakeup(const uint16_t pin_mask) +{ + RSTC->WKEN.reg &= ~(RSTC_WKEN_WKEN(pin_mask)); +} + +/** + * \brief Check whether any of the enabled wake up pins are active and caused the wakeup. + * + * Check whether any of the enabled wake up pins are active and caused the wakeup + * from backup sleep mode when exiting backup mode. + * + * \return Pin mask, the corresponding pin is active when its pin mask is 1. + */ +static inline uint16_t system_get_pin_wakeup_cause(void) +{ + return (RSTC_WKCAUSE_MASK & (RSTC->WKCAUSE.reg >> RSTC_WKCAUSE_WKCAUSE_Pos)); +} +#endif +/** + * @} + */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* RESET_H_INCLUDED */ diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/system/system.c b/src/boards/mcu/samr34/ASF/sam0/drivers/system/system.c new file mode 100644 index 000000000..6b17113cc --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/system/system.c @@ -0,0 +1,101 @@ +/** + * \file + * + * \brief SAM System related functionality + * + * Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#include + +/** + * \internal + * Dummy initialization function, used as a weak alias target for the various + * init functions called by \ref system_init(). + */ +void _system_dummy_init(void); +void _system_dummy_init(void) +{ + return; +} + +#if !defined(__DOXYGEN__) +# if defined(__GNUC__) +void system_clock_init(void) WEAK __attribute__((alias("_system_dummy_init"))); +void system_board_init(void) WEAK __attribute__((alias("_system_dummy_init"))); +void _system_events_init(void) WEAK __attribute__((alias("_system_dummy_init"))); +void _system_extint_init(void) WEAK __attribute__((alias("_system_dummy_init"))); +void _system_divas_init(void) WEAK __attribute__((alias("_system_dummy_init"))); +# elif defined(__ICCARM__) +void system_clock_init(void); +void system_board_init(void); +void _system_events_init(void); +void _system_extint_init(void); +void _system_divas_init(void); +# pragma weak system_clock_init=_system_dummy_init +# pragma weak system_board_init=_system_dummy_init +# pragma weak _system_events_init=_system_dummy_init +# pragma weak _system_extint_init=_system_dummy_init +# pragma weak _system_divas_init=_system_dummy_init +# endif +#endif + +/** + * \brief Initialize system + * + * This function will call the various initialization functions within the + * system namespace. If a given optional system module is not available, the + * associated call will effectively be a NOP (No Operation). + * + * Currently the following initialization functions are supported: + * - System clock initialization (via the SYSTEM CLOCK sub-module) + * - Board hardware initialization (via the Board module) + * - Event system driver initialization (via the EVSYS module) + * - External Interrupt driver initialization (via the EXTINT module) + */ +void system_init(void) +{ + /* Configure GCLK and clock sources according to conf_clocks.h */ + system_clock_init(); + + /* Initialize board hardware */ + system_board_init(); + + /* Initialize EVSYS hardware */ + _system_events_init(); + + /* Initialize External hardware */ + _system_extint_init(); + + /* Initialize DIVAS hardware */ + _system_divas_init(); +} + diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/system/system.h b/src/boards/mcu/samr34/ASF/sam0/drivers/system/system.h new file mode 100644 index 000000000..b2c31b9dc --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/system/system.h @@ -0,0 +1,721 @@ +/** + * \file + * + * \brief SAM System related functionality + * + * Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#ifndef SYSTEM_H_INCLUDED +#define SYSTEM_H_INCLUDED + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup asfdoc_sam0_system_group SAM System (SYSTEM) Driver + * + * This driver for Atmel® | SMART ARM®-based microcontrollers provides an interface for the configuration + * and management of the device's system relation functionality, necessary for + * the basic device operation. This is not limited to a single peripheral, but + * extends across multiple hardware peripherals. + * + * The following peripherals are used by this module: + * \if DEVICE_SAML21_SYSTEM_SUPPORT + * - PM (Power Manager) + * - RSTC (Reset Controller) + * - SUPC (Supply Controller) + * \endif + * \if DEVICE_SAMC21_SYSTEM_SUPPORT + * - PM (Power Manager) + * - RSTC (Reset Controller) + * - SUPC (Supply Controller) + * \endif + * \if DEVICE_SAMD21_SYSTEM_SUPPORT + * - SYSCTRL (System Control) + * - PM (Power Manager) + * \endif + * + * The following devices can use this module: + * \if DEVICE_SAML21_SYSTEM_SUPPORT + * - Atmel | SMART SAM L21 + * - Atmel | SMART SAM R30 + * - Atmel | SMART SAM R34 + * - Atmel | SMART SAM R35 + * \endif + * \if DEVICE_SAMC21_SYSTEM_SUPPORT + * - Atmel | SMART SAM C20/C21 + * \endif + * \if DEVICE_SAMD21_SYSTEM_SUPPORT + * - Atmel | SMART SAM D20/D21 + * - Atmel | SMART SAM R21 + * - Atmel | SMART SAM D09/D10/D11 + * - Atmel | SMART SAM DA1 + * \endif + * + * The outline of this documentation is as follows: + * - \ref asfdoc_sam0_system_prerequisites + * - \ref asfdoc_sam0_system_module_overview + * - \ref asfdoc_sam0_system_special_considerations + * - \ref asfdoc_sam0_system_extra_info + * - \ref asfdoc_sam0_system_examples + * - \ref asfdoc_sam0_system_api_overview + * + * + * \section asfdoc_sam0_system_prerequisites Prerequisites + * + * There are no prerequisites for this module. + * + * + * \section asfdoc_sam0_system_module_overview Module Overview + * + * The System driver provides a collection of interfaces between the user + * application logic, and the core device functionality (such as clocks, reset + * cause determination, etc.) that is required for all applications. It contains + * a number of sub-modules that control one specific aspect of the device: + * + * - System Core (this module) + * - \ref asfdoc_sam0_system_clock_group "System Clock Control" (sub-module) + * - \ref asfdoc_sam0_system_interrupt_group "System Interrupt Control" (sub-module) + * - \ref asfdoc_sam0_system_pinmux_group "System Pin Multiplexer Control" (sub-module) + * + * + * \if DEVICE_SAML21_SYSTEM_SUPPORT + * \subsection asfdoc_sam0_system_module_overview_vreg_l21 Voltage Regulator + * The SAM device controls the voltage regulators for the core (VDDCORE) and + * backup (VDDBU) domains. It sets the voltage regulators according to the sleep + * modes, the performance level, or the user configuration. + * + * In active mode, the voltage regulator can be chosen on the fly between a LDO + * or a Buck converter. In standby mode, the low power voltage regulator is used + * to supply VDDCORE. + * + * \subsection asfdoc_sam0_system_module_overview_bbps Battery Backup Power Switch + * The SAM device supports connection of a battery backup to the VBAT power pin. + * It includes functionality that enables automatic power switching between main + * power and battery backup power. This will ensure power to the backup domain, + * when the main battery or power source is unavailable. + * \endif + * + * \if DEVICE_SAMC21_SYSTEM_SUPPORT + * \subsection asfdoc_sam0_system_module_overview_vreg_c21 Voltage Regulator + * The SAM device controls the voltage regulators for the core (VDDCORE). It sets + * the voltage regulators according to the sleep modes. + * + * There are a selectable reference voltage and voltage dependent on the temperature + * which can be used by analog modules like the ADC. + * \endif + * + * \subsection asfdoc_sam0_system_module_overview_vref Voltage References + * The various analog modules within the SAM devices (such as AC, ADC, and + * DAC) require a voltage reference to be configured to act as a reference point + * for comparisons and conversions. + * + * The SAM devices contain multiple references, including an internal + * temperature sensor and a fixed band-gap voltage source. When enabled, the + * associated voltage reference can be selected within the desired peripheral + * where applicable. + * + * \subsection asfdoc_sam0_system_module_overview_reset_cause System Reset Cause + * In some applications there may be a need to execute a different program + * flow based on how the device was reset. For example, if the cause of reset + * was the Watchdog timer (WDT), this might indicate an error in the application, + * and a form of error handling or error logging might be needed. + * + * For this reason, an API is provided to retrieve the cause of the last system + * reset, so that appropriate action can be taken. + * + * \if DEVICE_SAML21_SYSTEM_SUPPORT + * There are three groups of reset sources: + * - Power supply reset: Resets caused by an electrical issue. It covers POR and BOD reset. + * - User reset: Resets caused by the application. It covers external reset, + * system reset, and watchdog reset. + * - Backup reset: Resets caused by a backup mode exit condition. + * + * \subsection asfdoc_sam0_system_module_overview_performance_level Performance Level + * Performance level allows the user to adjust the regulator output voltage to reduce + * power consumption. The user can on the fly select the most suitable performance + * level, depending on the application demands. + * + * The SAM device can operate at two different performance levels (PL0 and PL2). + * When operating at PL0, the voltage applied on the full logic area is reduced + * by voltage scaling. This voltage scaling technique allows to reduce the active + * power consumption while decreasing the maximum frequency of the device. When + * operating at PL2, the voltage regulator supplies the highest voltage, allowing + * the device to run at higher clock speeds. + * + * Performance level transition is possible only when the device is in active + * mode. After a reset, the device starts at the lowest performance level + * (lowest power consumption and lowest max. frequency). The application can then + * switch to another performance level at any time without any stop in the code + * execution. As shown in \ref asfdoc_sam0_system_performance_level_transition_figure. + * + * \note When scaling down the performance level, the bus frequency should first be + * scaled down in order to not exceed the maximum frequency allowed for the + * low performance level. + * When scaling up the performance level (e.g. from PL0 to PL2), check the performance + * level status before increasing the bus frequency. It can be increased only + * when the performance level transition is completed. + * + * \anchor asfdoc_sam0_system_performance_level_transition_figure + * \image html performance_level_transition.svg "Performance Level Transition" + * + * \subsection asfdoc_sam0_system_module_overview_power_domain Power Domain Gating + * Power domain gating allows power saving by reducing the voltage in logic + * areas in the device to a low-power supply. The feature is available in + * Standby sleep mode and will reduce the voltage in domains where all peripherals + * are idle. Internal logic will maintain its content, meaning the corresponding + * peripherals will not need to be reconfigured when normal operating voltage + * is returned. Most power domains can be in the following three states: + * + * - Active state: The power domain is powered on. + * - Retention state: The main voltage supply for the power domain is switched off, + * while maintaining a secondary low-power supply for the sequential cells. The + * logic context is restored when waking up. + * - Off state: The power domain is entirely powered off. The logic context is lost. + * + * The SAM L21 device contains three power domains which can be controlled using + * power domain gating, namely PD0, PD1, and PD2. These power domains can be + * configured to the following cases: + * - Default with no sleepwalking peripherals: A power domain is automatically set + * to retention state in standby sleep mode if no activity require it. The application + * can force all power domains to remain in active state during standby sleep mode + * in order to accelerate wakeup time. + * - Default with sleepwalking peripherals: If one or more peripherals are enabled + * to perform sleepwalking tasks in standby sleep mode, the corresponding power + * domain (PDn) remains in active state as well as all inferior power domains (PDn) in order + * to perform a sleepwalking task. The superior power domain is then automatically + * set to active state. At the end of the sleepwalking task, the device can either + * be woken up or the superior power domain can return to retention state. + * + * Power domains can be linked to each other, it allows a power domain (PDn) to be kept + * in active state if the inferior power domain (PDn-1) is in active state too. + * + * \ref asfdoc_sam0_system_power_domain_overview_table illustrates the + * four cases to consider in standby mode. + * + * \anchor asfdoc_sam0_system_power_domain_overview_table + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Sleep Mode versus Power Domain State Overview
Sleep modePD0PD1PD2PDTOPPDBACKUP
Idleactiveactiveactiveactiveactive
Standby - Case 1activeactiveactiveactiveactive
Standby - Case 2activeactiveretentionactiveactive
Standby - Case 3activeretentionretentionactiveactive
Standby - Case 4retentionretentionretentionactiveactive
Backupoffoffoffoffactive
Offoffoffoffoffoff
+ * + * \subsection asfdoc_sam0_system_module_overview_ram_state RAMs Low Power Mode + * By default, in standby sleep mode, RAM is in low power mode (back biased) + * if its power domain is in retention state. + * \ref asfdoc_sam0_system_power_ram_state_table lists RAMs low power mode. + * + * \anchor asfdoc_sam0_system_power_ram_state_table + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
RAM Back-biasing Mode
RAM modeDescription
Retention Back-biasing modeRAM is back-biased if its power domain is in retention mode
Standby Back-biasing modeRAM is back-biased if the device is in standby mode
Standby OFF modeRAM is OFF if the device is in standby mode
Always OFF modeRAM is OFF if the device is in RET mode
+ * + * \endif + * + * \subsection asfdoc_sam0_system_module_overview_sleep_mode Sleep Modes + * The SAM devices have several sleep modes. The sleep mode controls + * which clock systems on the device will remain enabled or disabled when the + * device enters a low power sleep mode. + * \ref asfdoc_sam0_system_module_sleep_mode_table "The table below" lists the + * clock settings of the different sleep modes. + * + * \anchor asfdoc_sam0_system_module_sleep_mode_table + * + * + * \if DEVICE_SAML21_SYSTEM_SUPPORT + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * \else + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * \endif + *
SAM Device Sleep Modes
Sleep modeSystem clockCPU clockAHB/AHB clockGCLK clocksOscillators (ONDEMAND = 0)Oscillators (ONDEMAND = 1)Regulator modeRAM mode
IdleRunStopRun if requestedRunRunRun if requestedNormalNormal
StandbyStopStopRun if requestedRun if requestedRun if requested or RUNSTDBY = 1Run if requestedLow pwerLow pwer
BackupStopStopStopStopStopStopBackupOff
OffOffOffOffOffOffOffOffOff
Sleep modeCPU clockAHB clockAPB clocksClock sourcesSystem clock32KHzReg modeRAM mode
Idle 0StopRunRunRunRunRunNormalNormal
Idle 1StopStopRunRunRunRunNormalNormal
Idle 2StopStopStopRunRunRunNormalNormal
StandbyStopStopStopStopStopStopLow PowerSource/Drain biasing
+ * + * Before entering device sleep, one of the available sleep modes must be set. + * The device will automatically wake up in response to an interrupt being + * generated or upon any other sleep mode exit condition. + * + * Some peripheral clocks will remain enabled during sleep, depending on their + * configuration. If desired, the modules can remain clocked during sleep to allow + * them continue to operate while other parts of the system are powered down + * to save power. + * + * + * \section asfdoc_sam0_system_special_considerations Special Considerations + * + * Most of the functions in this driver have device specific restrictions and + * caveats; refer to your device datasheet. + * + * + * \section asfdoc_sam0_system_extra_info Extra Information + * + * For extra information, see \ref asfdoc_sam0_system_extra. This includes: + * - \ref asfdoc_sam0_system_extra_acronyms + * - \ref asfdoc_sam0_system_extra_dependencies + * - \ref asfdoc_sam0_system_extra_errata + * - \ref asfdoc_sam0_system_extra_history + * + * + * \section asfdoc_sam0_system_examples Examples + * + * For SYSTEM module related examples, refer to the sub-modules listed in + * the \ref asfdoc_sam0_system_module_overview "Module Overview". + * + * \if DEVICE_SAML21_SYSTEM_SUPPORT + * For a list of examples related to this driver, see + * \ref asfdoc_sam0_drivers_power_exqsg. + * \endif + * + * + * \section asfdoc_sam0_system_api_overview API Overview + * @{ + */ + +/** + * \name System Debugger + * @{ + */ + +/** + * \brief Check if debugger is present. + * + * Check if debugger is connected to the onboard debug system (DAP). + * + * \return A bool identifying if a debugger is present. + * + * \retval true Debugger is connected to the system + * \retval false Debugger is not connected to the system + * + */ +static inline bool system_is_debugger_present(void) +{ + return DSU->STATUSB.reg & DSU_STATUSB_DBGPRES; +} + +/** + * @} + */ + +/** + * \name System Identification + * @{ + */ + +/** + * \brief Retrieve the device identification signature. + * + * Retrieves the signature of the current device. + * + * \return Device ID signature as a 32-bit integer. + */ +static inline uint32_t system_get_device_id(void) +{ + return DSU->DID.reg; +} + +/** + * @} + */ + +/** + * \name System Initialization + * @{ + */ + +void system_init(void); + +/** + * @} + */ + + +/** + * @} + */ + +/** + * + * \if DEVICE_SAML21_SYSTEM_SUPPORT + * \page asfdoc_sam0_drivers_power_exqsg Examples for SYSTEM Driver + * + * This is a list of the available Quick Start Guides (QSGs) and example + * applications for \ref asfdoc_sam0_system_group. QSGs are simple examples with step-by-step instructions to + * configure and use this driver in a selection of + * use cases. Note that a QSG can be compiled as a standalone application or be + * added to the user application. + * + * - \subpage asfdoc_sam0_power_basic_use_case + * \endif + * + * \page asfdoc_sam0_system_extra Extra Information for SYSTEM Driver + * + * \section asfdoc_sam0_system_extra_acronyms Acronyms + * Below is a table listing the acronyms used in this module, along with their + * intended meanings. + * + * + * + * + * + * + * + * + * + * + * \if DEVICE_SAML21_SYSTEM_SUPPORT + * + * + * + * + * + * + * + * + * \endif + * \if DEVICE_SAMC21_SYSTEM_SUPPORT + * + * + * + * + * + * + * + * + * \endif + * \if DEVICE_SAMD21_SYSTEM_SUPPORT + * + * + * + * + * \endif + *
AcronymDefinition
PMPower Manager
SUPCSupply Controller
RSTCReset Controller
SUPCSupply Controller
RSTCReset Controller
SYSCTRLSystem control interface
+ * + * + * \section asfdoc_sam0_system_extra_dependencies Dependencies + * This driver has the following dependencies: + * + * - None + * + * + * \section asfdoc_sam0_system_extra_errata Errata + * There are no errata related to this driver. + * + * + * \section asfdoc_sam0_system_extra_history Module History + * An overview of the module history is presented in the table below, with + * details on the enhancements and fixes made to the module since its first + * release. The current version of this corresponds to the newest version in + * the table. + * + * + * + * + * + * \if DEVICE_SAML21_SYSTEM_SUPPORT + * + * + * + * \endif + * \if DEVICE_SAMC21_SYSTEM_SUPPORT + * + * + * + * \endif + * \if DEVICE_SAMD21_SYSTEM_SUPPORT + * + * + * + * + * + * + * + * + * + * \endif + *
Changelog
Initial Release
Initial Release
Added new \c system_reset() to reset the complete MCU with some exceptions
Added new \c system_get_device_id() function to retrieved the device + * ID
Initial Release
+ * + * \page asfdoc_sam0_system_document_revision_history Document Revision History + * + * + * + * + * + * + * + * \if DEVICE_SAML21_SYSTEM_SUPPORT + * + * + * + * + * + * \endif + * \if DEVICE_SAMC21_SYSTEM_SUPPORT + * + * + * + * + * + * \endif + * \if DEVICE_SAMD21_SYSTEM_SUPPORT + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * \endif + *
Doc. Rev.DateComments
42449A07/2015Initial document release
42484A12/2015Initial document release.
42120E12/2015Added support for SAM DA1 and SAM D09
42120D12/2014Added support for SAM R21 and SAM D10/D11
42120C01/2014Added support for SAM D21
42120B06/2013Corrected documentation typos
42120A06/2013Initial document release
+ */ + +#ifdef __cplusplus +} +#endif + +#endif /* SYSTEM_H_INCLUDED */ + diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/tc/tc.h b/src/boards/mcu/samr34/ASF/sam0/drivers/tc/tc.h new file mode 100644 index 000000000..0dbdaa8ca --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/tc/tc.h @@ -0,0 +1,1788 @@ +/** + * \file + * + * \brief SAM TC - Timer Counter Driver + * + * Copyright (c) 2013-2020 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#ifndef TC_H_INCLUDED +#define TC_H_INCLUDED + +/** + * \defgroup asfdoc_sam0_tc_group SAM Timer/Counter (TC) Driver + * + * This driver for Atmel® | SMART ARM®-based microcontrollers provides an interface for the configuration + * and management of the timer modules within the device, for waveform + * generation and timing operations. The following driver API modes are covered + * by this manual: + * + * - Polled APIs + * \if TC_CALLBACK_MODE + * - Callback APIs + * \endif + * + * + * The following peripheral is used by this module: + * - TC (Timer/Counter) + * + * The following devices can use this module: + * - Atmel | SMART SAM D20/D21 + * - Atmel | SMART SAM R21 + * - Atmel | SMART SAM D09/D10/D11 + * - Atmel | SMART SAM L21/L22 + * - Atmel | SMART SAM DA1 + * - Atmel | SMART SAM C20/C21 + * - Atmel | SMART SAM HA1 + * - Atmel | SMART SAM R30 + * - Atmel | SMART SAM R34 + * - Atmel | SMART SAM R35 + * + * The outline of this documentation is as follows: + * - \ref asfdoc_sam0_tc_prerequisites + * - \ref asfdoc_sam0_tc_module_overview + * - \ref asfdoc_sam0_tc_special_considerations + * - \ref asfdoc_sam0_tc_extra_info + * - \ref asfdoc_sam0_tc_examples + * - \ref asfdoc_sam0_tc_api_overview + * + * + * \section asfdoc_sam0_tc_prerequisites Prerequisites + * + * There are no prerequisites for this module. + * + * + * \section asfdoc_sam0_tc_module_overview Module Overview + * + * The Timer/Counter (TC) module provides a set of timing and counting related + * functionality, such as the generation of periodic waveforms, the capturing + * of a periodic waveform's frequency/duty cycle, and software timekeeping for + * periodic operations. TC modules can be configured to use an 8-, 16-, or + * 32-bit counter size. + * + * This TC module for the SAM is capable of the following functions: + * + * - Generation of PWM signals + * - Generation of timestamps for events + * - General time counting + * - Waveform period capture + * - Waveform frequency capture + * + * \ref asfdoc_sam0_tc_block_diagram "The diagram below" shows the overview + * of the TC module design. + * + * \anchor asfdoc_sam0_tc_block_diagram + * \image html overview.svg "Basic Overview of the TC Module" + * + * + * \subsection asfdoc_sam0_tc_features Driver Feature Macro Definition + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Driver Feature MacroSupported devices
FEATURE_TC_DOUBLE_BUFFEREDSAM L21/L22/C20/C21/R30/R34/R35
FEATURE_TC_SYNCBUSY_SCHEME_VERSION_2SAM L21/L22/C20/C21/R30/R34/R35
FEATURE_TC_STAMP_PW_CAPTURESAM L21/L22/C20/C21/R30/R34/R35
FEATURE_TC_READ_SYNCSAM L21/L22/C20/C21/R30/R34/R35
FEATURE_TC_IO_CAPTURESAM L21/L22/C20/C21/R30/R34/R35
FEATURE_TC_GENERATE_DMA_TRIGGERSAM L21/L22/R30/R34/R35
+ * \note The specific features are only available in the driver when the + * selected device supports those features. + * + * \subsection asfdoc_sam0_tc_module_overview_func_desc Functional Description + * Independent of the configured counter size, each TC module can be set up + * in one of two different modes; capture and compare. + * + * In capture mode, the counter value is stored when a configurable event + * occurs. This mode can be used to generate timestamps used in event capture, + * or it can be used for the measurement of a periodic input signal's + * frequency/duty cycle. + * + * In compare mode, the counter value is compared against one or more of the + * configured channel compare values. When the counter value coincides with a + * compare value an action can be taken automatically by the module, such as + * generating an output event or toggling a pin when used for frequency or + * Pulse Width Modulation (PWM) signal generation. + * + * \note The connection of events between modules requires the use of the + * \ref asfdoc_sam0_events_group "SAM Event System Driver (EVENTS)" + * to route output event of one module to the input event of another. + * For more information on event routing, refer to the event driver + * documentation. + * + * \subsection asfdoc_sam0_tc_module_overview_tc_size Timer/Counter Size + * Each timer module can be configured in one of three different counter + * sizes; 8-, 16-, and 32-bit. The size of the counter determines the maximum + * value it can count to before an overflow occurs and the count is reset back + * to zero. \ref asfdoc_sam0_tc_count_size_vs_top "The table below" shows the + * maximum values for each of the possible counter sizes. + * + * \anchor asfdoc_sam0_tc_count_size_vs_top + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Timer Counter Sizes and Their Maximum Count Values
Counter sizeMax. (hexadecimal)Max. (decimal)
8-bit0xFF255
16-bit0xFFFF65,535
32-bit0xFFFFFFFF4,294,967,295
+ * + * When using the counter in 16- or 32-bit count mode, Compare Capture + * register 0 (CC0) is used to store the period value when running in PWM + * generation match mode. + * + * When using 32-bit counter size, two 16-bit counters are chained together + * in a cascade formation. Except in SAM D09/D10/D11. Even numbered TC modules + * (e.g. TC0, TC2) can be configured as 32-bit counters. The odd numbered + * counters will act as slaves to the even numbered masters, and will not + * be reconfigurable until the master timer is disabled. The pairing of timer + * modules for 32-bit mode is shown in \ref asfdoc_sam0_tc_module_ms_pairs + * "the table below". + * + * \anchor asfdoc_sam0_tc_module_ms_pairs + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
TC Master and Slave Module Pairings
Master TC moduleSlave TC module
TC0TC1
TC2TC3
......
TCn-1TCn
+ * + * In SAM D09/D10/D11, odd numbered TC modules (e.g. TC1) can be configured as 32-bit + * counters. The even numbered (e.g. TC2) counters will act as slaves to the odd + * numbered masters. + * + * \subsection asfdoc_sam0_tc_module_overview_clock Clock Settings + * + * \subsubsection asfdoc_sam0_tc_module_overview_clock_selection Clock Selection + * Each TC peripheral is clocked asynchronously to the system clock by a GCLK + * (Generic Clock) channel. The GCLK channel connects to any of the GCLK + * generators. The GCLK generators are configured to use one of the available + * clock sources on the system such as internal oscillator, external crystals, + * etc. See the \ref asfdoc_sam0_system_clock_group "Generic Clock driver" + *for + * more information. + * + * \subsubsection asfdoc_sam0_tc_module_overview_clock_prescaler Prescaler + * Each TC module in the SAM has its own individual clock prescaler, which + * can be used to divide the input clock frequency used in the counter. This + * prescaler only scales the clock used to provide clock pulses for the counter + * to count, and does not affect the digital register interface portion of + * the module, thus the timer registers will synchronize to the raw GCLK + * frequency input to the module. + * + * As a result of this, when selecting a GCLK frequency and timer prescaler + * value the user application should consider both the timer resolution + * required and the synchronization frequency, to avoid lengthy + * synchronization times of the module if a very slow GCLK frequency is fed + * into the TC module. It is preferable to use a higher module GCLK frequency + * as the input to the timer, and prescale this down as much as possible to + * obtain a suitable counter frequency in latency-sensitive applications. + * + * \subsubsection asfdoc_sam0_tc_module_overview_clock_reloading Reloading + * Timer modules also contain a configurable reload action, used when a + * re-trigger event occurs. Examples of a re-trigger event are the counter + * reaching the maximum value when counting up, or when an event from the event + * system tells the counter to re-trigger. The reload action determines if the + * prescaler should be reset, and when this should happen. The counter will + * always be reloaded with the value it is set to start counting from. The user + * can choose between three different reload actions, described in + * \ref asfdoc_sam0_tc_module_reload_act "the table below". + * + * \anchor asfdoc_sam0_tc_module_reload_act + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
TC Module Reload Actions
Reload actionDescription
\ref TC_RELOAD_ACTION_GCLK Reload TC counter value on next GCLK cycle. Leave prescaler + * as-is.
\ref TC_RELOAD_ACTION_PRESC Reloads TC counter value on next prescaler clock. Leave prescaler + * as-is.
\ref TC_RELOAD_ACTION_RESYNC Reload TC counter value on next GCLK cycle. Clear prescaler to + * zero.
+ * + * The reload action to use will depend on the specific application being + * implemented. One example is when an external trigger for a reload occurs; if + * the TC uses the prescaler, the counter in the prescaler should not have a + * value between zero and the division factor. The TC counter and the counter + * in the prescaler should both start at zero. When the counter is set to + * re-trigger when it reaches the maximum value on the other hand, this is not the + * right option to use. In such a case it would be better if the prescaler is + * left unaltered when the re-trigger happens, letting the counter reset on the + * next GCLK cycle. + * + * \subsection asfdoc_sam0_tc_module_overview_compare_match Compare Match Operations + * In compare match operation, Compare/Capture registers are used in comparison + * with the counter value. When the timer's count value matches the value of a + * compare channel, a user defined action can be taken. + * + * \subsubsection asfdoc_sam0_tc_module_overview_compare_match_timer Basic Timer + * + * A Basic Timer is a simple application where compare match operations are used + * to determine when a specific period has elapsed. In Basic Timer operations, + * one or more values in the module's Compare/Capture registers are used to + * specify the time (as a number of prescaled GCLK cycles) when an action should + * be taken by the microcontroller. This can be an Interrupt Service Routine + * (ISR), event generator via the event system, or a software flag that is + * polled via the user application. + * + * \subsubsection asfdoc_sam0_tc_module_overview_compare_match_wg Waveform Generation + * + * Waveform generation enables the TC module to generate square waves, or if + * combined with an external passive low-pass filter; analog waveforms. + * + * \subsubsection asfdoc_sam0_tc_module_overview_compare_match_wg_pwm Waveform Generation - PWM + * + * Pulse width modulation is a form of waveform generation and a signalling + * technique that can be useful in many situations. When PWM mode is used, + * a digital pulse train with a configurable frequency and duty cycle can be + * generated by the TC module and output to a GPIO pin of the device. + * + * Often PWM is used to communicate a control or information parameter to an + * external circuit or component. Differing impedances of the source generator + * and sink receiver circuits are less of an issue when using PWM compared to + * using an analog voltage value, as noise will not generally affect the + * signal's integrity to a meaningful extent. + * + * \ref asfdoc_sam0_tc_module_pwm_normal_diag "The figure below" illustrates + * operations and different states of the counter and its output when running + * the counter in PWM normal mode. As can be seen, the TOP value is unchanged + * and is set to MAX. The compare match value is changed at several points to + * illustrate the resulting waveform output changes. The PWM output is set to + * normal (i.e. non-inverted) output mode. + * + * \anchor asfdoc_sam0_tc_module_pwm_normal_diag + * \image html pwm_normal_ex.svg "Example of PWM in Normal Mode, and Different Counter Operations" + * + * + * In \ref asfdoc_sam0_tc_module_pwm_match_diag "the figure below", the + * counter is set to generate PWM in Match mode. The PWM output is inverted via + * the appropriate configuration option in the TC driver configuration + * structure. In this example, the counter value is changed once, but the + * compare match value is kept unchanged. As can be seen, it is possible to + * change the TOP value when running in PWM match mode. + * + * \anchor asfdoc_sam0_tc_module_pwm_match_diag + * \image html pwm_match_ex.svg "Example of PWM in Match Mode and Different Counter Operations" + * + * \subsubsection asfdoc_sam0_tc_module_overview_compare_match_wg_freq Waveform Generation - Frequency + * + * Frequency Generation mode is in many ways identical to PWM + * generation. However, in Frequency Generation a toggle only occurs + * on the output when a match on a capture channels occurs. When the + * match is made, the timer value is reset, resulting in a variable + * frequency square wave with a fixed 50% duty cycle. + * + * \subsubsection asfdoc_sam0_tc_module_overview_compare_match_capt Capture Operations + * + * In capture operations, any event from the event system or a pin change can + * trigger a capture of the counter value. This captured counter value can be + * used as a timestamp for the event, or it can be used in frequency and pulse + * width capture. + * + * \subsubsection asfdoc_sam0_tc_module_overview_compare_match_capt_event_capture Capture Operations - Event + * + * Event capture is a simple use of the capture functionality, + * designed to create timestamps for specific events. When the TC + * module's input capture pin is externally toggled, the current timer + * count value is copied into a buffered register which can then be + * read out by the user application. + * + * Note that when performing any capture operation, there is a risk that the + * counter reaches its top value (MAX) when counting up, or the bottom value + * (zero) when counting down, before the capture event occurs. This can distort + * the result, making event timestamps to appear shorter than reality; the + * user application should check for timer overflow when reading a capture + * result in order to detect this situation and perform an appropriate + * adjustment. + * + * Before checking for a new capture, \ref TC_STATUS_COUNT_OVERFLOW + * should be checked. The response to an overflow error is left to the user + * application, however it may be necessary to clear both the capture overflow + * flag and the capture flag upon each capture reading. + * + * \subsubsection asfdoc_sam0_tc_module_overview_compare_match_capt_pwc Capture Operations - Pulse Width + * + * Pulse Width Capture mode makes it possible to measure the pulse width and + * period of PWM signals. This mode uses two capture channels of the counter. + * This means that the counter module used for Pulse Width Capture can not be + * used for any other purpose. There are two modes for pulse width capture; + * Pulse Width Period (PWP) and Period Pulse Width (PPW). In PWP mode, capture + * channel 0 is used for storing the pulse width and capture channel 1 stores + * the observed period. While in PPW mode, the roles of the two capture channels + * are reversed. + * + * As in the above example it is necessary to poll on interrupt flags to see + * if a new capture has happened and check that a capture overflow error has + * not occurred. + * + * \subsection asfdoc_sam0_tc_module_overview_oneshot One-shot Mode + * + * TC modules can be configured into a one-shot mode. When configured in this + * manner, starting the timer will cause it to count until the next overflow + * or underflow condition before automatically halting, waiting to be manually + * triggered by the user application software or an event signal from the event + * system. + * + * \subsubsection asfdoc_sam0_tc_module_overview_inversion Wave Generation Output Inversion + * + * The output of the wave generation can be inverted by hardware if desired, + * resulting in the logically inverted value being output to the configured + * device GPIO pin. + * + * + * \section asfdoc_sam0_tc_special_considerations Special Considerations + * + * The number of capture compare registers in each TC module is dependent on + * the specific SAM device being used, and in some cases the counter size. + * + * The maximum amount of capture compare registers available in any SAM + * device is two when running in 32-bit mode and four in 8- and 16-bit modes. + * + * + * \section asfdoc_sam0_tc_extra_info Extra Information + * + * For extra information, see \ref asfdoc_sam0_tc_extra. This includes: + * - \ref asfdoc_sam0_tc_extra_acronyms + * - \ref asfdoc_sam0_tc_extra_dependencies + * - \ref asfdoc_sam0_tc_extra_errata + * - \ref asfdoc_sam0_tc_extra_history + * + * + * \section asfdoc_sam0_tc_examples Examples + * + * For a list of examples related to this driver, see + * \ref asfdoc_sam0_tc_exqsg. + * + * \section asfdoc_sam0_tc_api_overview API Overview + * @{ + */ + +#include +#include +#include +#include + +/** + * Define port features set according to different device family + * @{ +*/ +#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30)|| (SAMR34) || (SAMR35) || (WLR089) || defined(__DOXYGEN__) +/** TC double buffered. */ +# define FEATURE_TC_DOUBLE_BUFFERED +/** SYNCBUSY scheme version 2. */ +# define FEATURE_TC_SYNCBUSY_SCHEME_VERSION_2 +/** TC time stamp capture and pulse width capture. */ +# define FEATURE_TC_STAMP_PW_CAPTURE +/** Read synchronization of COUNT. */ +# define FEATURE_TC_READ_SYNC +/** I/O pin edge capture. */ +# define FEATURE_TC_IO_CAPTURE +#endif + +#if (SAML21XXXB) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) || defined(__DOXYGEN__) +/** Generate Direct Memory Access (DMA) triggers. */ +# define FEATURE_TC_GENERATE_DMA_TRIGGER +#endif +/*@}*/ + +#if !defined(__DOXYGEN__) +#if SAMD20 || SAML21 || SAML22 || SAMC20 || SAMC21 || SAMR30 || (SAMR34) || (SAMR35) || (WLR089) +# define TC_INSTANCE_OFFSET 0 +#endif +#if SAMD21 || SAMR21 || SAMDA1 || (SAMHA1) || (SAMHA0) +# define TC_INSTANCE_OFFSET 3 +#endif +#if SAMD09 || SAMD10 || SAMD11 +# define TC_INSTANCE_OFFSET 1 +#endif + +#if SAMD20 +# define NUMBER_OF_COMPARE_CAPTURE_CHANNELS TC0_CC8_NUM +#elif SAML21 || SAML22 || SAMC20 || SAMC21 || SAMR30 || (SAMR34) || (SAMR35) || (WLR089) +# define NUMBER_OF_COMPARE_CAPTURE_CHANNELS TC0_CC_NUM +#elif SAMD09 || SAMD10 || SAMD11 +# define NUMBER_OF_COMPARE_CAPTURE_CHANNELS TC1_CC8_NUM +#else +# define NUMBER_OF_COMPARE_CAPTURE_CHANNELS TC3_CC8_NUM + /* Same number for 8-, 16- or 32-bit TC and all TC instances */ +#endif + +/** TC Instance MAX ID Number. */ +#if SAMD20E || SAMD20G || SAMD21G || SAMD21E || SAMR21 +# if SAMD21GXXL || SAM_PART_IS_DEFINED(SAMD21G17AU) || SAM_PART_IS_DEFINED(SAMD21G18AU) +# define TC_INST_MAX_ID 7 +# else +# define TC_INST_MAX_ID 5 +# endif +#elif SAML21 || SAMC20 || SAMC21 || SAMR30 || (SAMR34) || (SAMR35) || (WLR089) +# define TC_INST_MAX_ID 4 +#elif SAML22 +# define TC_INST_MAX_ID 3 +#elif SAMD09 || SAMD10 || SAMD11 +# define TC_INST_MAX_ID 2 +#else +# define TC_INST_MAX_ID 7 +#endif + +#endif + +#if TC_ASYNC == true +# include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if TC_ASYNC == true +/** Enum for the possible callback types for the TC module. */ +enum tc_callback { + /** Callback for TC overflow */ + TC_CALLBACK_OVERFLOW, + /** Callback for capture overflow error */ + TC_CALLBACK_ERROR, + /** Callback for capture compare channel 0 */ + TC_CALLBACK_CC_CHANNEL0, + /** Callback for capture compare channel 1 */ + TC_CALLBACK_CC_CHANNEL1, +# if !defined(__DOXYGEN__) + /** Number of available callbacks */ + TC_CALLBACK_N, +# endif +}; +#endif + +/** + * \name Module Status Flags + * + * TC status flags, returned by \ref tc_get_status() and cleared by + * \ref tc_clear_status(). + * + * @{ + */ + +/** Timer channel 0 has matched against its compare value, or has captured a + * new value. + */ +#define TC_STATUS_CHANNEL_0_MATCH (1UL << 0) + +/** Timer channel 1 has matched against its compare value, or has captured a + * new value. + */ +#define TC_STATUS_CHANNEL_1_MATCH (1UL << 1) + +/** Timer register synchronization has completed, and the synchronized count + * value may be read. + */ +#define TC_STATUS_SYNC_READY (1UL << 2) + +/** A new value was captured before the previous value was read, resulting in + * lost data. + */ +#define TC_STATUS_CAPTURE_OVERFLOW (1UL << 3) + +/** The timer count value has overflowed from its maximum value to its minimum + * when counting upward, or from its minimum value to its maximum when + * counting downward. + */ +#define TC_STATUS_COUNT_OVERFLOW (1UL << 4) + +#ifdef FEATURE_TC_DOUBLE_BUFFERED +/** Channel 0 compare or capture buffer valid. */ +#define TC_STATUS_CHN0_BUFFER_VALID (1UL << 5) +/** Channel 1 compare or capture buffer valid. */ +#define TC_STATUS_CHN1_BUFFER_VALID (1UL << 6) +/** Period buffer valid. */ +#define TC_STATUS_PERIOD_BUFFER_VALID (1UL << 7) +#endif +/** @} */ + +/** + * \brief Index of the compare capture channels. + * + * This enum is used to specify which capture/compare channel to do + * operations on. + */ +enum tc_compare_capture_channel { + /** Index of compare capture channel 0 */ + TC_COMPARE_CAPTURE_CHANNEL_0, + /** Index of compare capture channel 1 */ + TC_COMPARE_CAPTURE_CHANNEL_1, +}; + +/** + * \name TC Wave Generation Mode + * + * @{ + */ +#if SAML21 || SAML22 || SAMC20 || SAMC21 || SAMR30 || (SAMR34) || (SAMR35) || (WLR089) +/** TC wave generation mode: normal frequency. */ +#define TC_WAVE_GENERATION_NORMAL_FREQ_MODE TC_WAVE_WAVEGEN_NFRQ +/** TC wave generation mode: match frequency. */ +#define TC_WAVE_GENERATION_MATCH_FREQ_MODE TC_WAVE_WAVEGEN_MFRQ +/** TC wave generation mode: normal PWM. */ +#define TC_WAVE_GENERATION_NORMAL_PWM_MODE TC_WAVE_WAVEGEN_NPWM +/** TC wave generation mode: match PWM. */ +#define TC_WAVE_GENERATION_MATCH_PWM_MODE TC_WAVE_WAVEGEN_MPWM +#else +/** TC wave generation mode: normal frequency. */ +#define TC_WAVE_GENERATION_NORMAL_FREQ_MODE TC_CTRLA_WAVEGEN_NFRQ +/** TC wave generation mode: match frequency. */ +#define TC_WAVE_GENERATION_MATCH_FREQ_MODE TC_CTRLA_WAVEGEN_MFRQ +/** TC wave generation mode: normal PWM. */ +#define TC_WAVE_GENERATION_NORMAL_PWM_MODE TC_CTRLA_WAVEGEN_NPWM +/** TC wave generation mode: match PWM. */ +#define TC_WAVE_GENERATION_MATCH_PWM_MODE TC_CTRLA_WAVEGEN_MPWM +#endif +/** @} */ + +/** + * \brief TC wave generation mode enum. + * + * This enum is used to select which mode to run the wave + * generation in. + * + */ +enum tc_wave_generation { + /** Top is maximum, except in 8-bit counter size where it is the PER + * register + */ + TC_WAVE_GENERATION_NORMAL_FREQ = TC_WAVE_GENERATION_NORMAL_FREQ_MODE, + + /** Top is CC0, except in 8-bit counter size where it is the PER + * register + */ + TC_WAVE_GENERATION_MATCH_FREQ = TC_WAVE_GENERATION_MATCH_FREQ_MODE, + + /** Top is maximum, except in 8-bit counter size where it is the PER + * register + */ + TC_WAVE_GENERATION_NORMAL_PWM = TC_WAVE_GENERATION_NORMAL_PWM_MODE, + + /** Top is CC0, except in 8-bit counter size where it is the PER + * register + */ + TC_WAVE_GENERATION_MATCH_PWM = TC_WAVE_GENERATION_MATCH_PWM_MODE, +}; + +/** + * \brief Specifies if the counter is 8-, 16-, or 32-bit. + * + * This enum specifies the maximum value it is possible to count to. + */ +enum tc_counter_size { + /** The counter's maximum value is 0xFF, the period register is + * available to be used as top value + */ + TC_COUNTER_SIZE_8BIT = TC_CTRLA_MODE_COUNT8, + + /** The counter's maximum value is 0xFFFF. There is no separate + * period register, to modify top one of the capture compare + * registers has to be used. This limits the amount of + * available channels. + */ + TC_COUNTER_SIZE_16BIT = TC_CTRLA_MODE_COUNT16, + + /** The counter's maximum value is 0xFFFFFFFF. There is no separate + * period register, to modify top one of the capture compare + * registers has to be used. This limits the amount of + * available channels. + */ + TC_COUNTER_SIZE_32BIT = TC_CTRLA_MODE_COUNT32, +}; + +/** + * \brief TC Counter reload action enum. + * + * This enum specify how the counter and prescaler should reload. + */ +enum tc_reload_action { + /** The counter is reloaded/reset on the next GCLK and starts + * counting on the prescaler clock + */ + TC_RELOAD_ACTION_GCLK = TC_CTRLA_PRESCSYNC_GCLK, + + /** The counter is reloaded/reset on the next prescaler clock + */ + TC_RELOAD_ACTION_PRESC = TC_CTRLA_PRESCSYNC_PRESC, + + /** The counter is reloaded/reset on the next GCLK, and the + * prescaler is restarted as well + */ + TC_RELOAD_ACTION_RESYNC = TC_CTRLA_PRESCSYNC_RESYNC, +}; + +/** + * \brief TC clock prescaler values. + * + * This enum is used to choose the clock prescaler + * configuration. The prescaler divides the clock frequency of the TC + * module to make the counter count slower. + */ +enum tc_clock_prescaler { + /** Divide clock by 1 */ + TC_CLOCK_PRESCALER_DIV1 = TC_CTRLA_PRESCALER(0), + /** Divide clock by 2 */ + TC_CLOCK_PRESCALER_DIV2 = TC_CTRLA_PRESCALER(1), + /** Divide clock by 4 */ + TC_CLOCK_PRESCALER_DIV4 = TC_CTRLA_PRESCALER(2), + /** Divide clock by 8 */ + TC_CLOCK_PRESCALER_DIV8 = TC_CTRLA_PRESCALER(3), + /** Divide clock by 16 */ + TC_CLOCK_PRESCALER_DIV16 = TC_CTRLA_PRESCALER(4), + /** Divide clock by 64 */ + TC_CLOCK_PRESCALER_DIV64 = TC_CTRLA_PRESCALER(5), + /** Divide clock by 256 */ + TC_CLOCK_PRESCALER_DIV256 = TC_CTRLA_PRESCALER(6), + /** Divide clock by 1024 */ + TC_CLOCK_PRESCALER_DIV1024 = TC_CTRLA_PRESCALER(7), +}; + +/** + * \brief TC module count direction. + * + * Timer/Counter count direction. + */ +enum tc_count_direction { + /** Timer should count upward from zero to MAX */ + TC_COUNT_DIRECTION_UP, + + /** Timer should count downward to zero from MAX */ + TC_COUNT_DIRECTION_DOWN, +}; + +/** + * \name Waveform Inversion Mode + * + * @{ + */ +#if SAML21 || SAML22 || SAMC20 || SAMC21 || SAMR30 || (SAMR34) || (SAMR35) || (WLR089) +/** Waveform inversion CC0 mode. */ +#define TC_WAVEFORM_INVERT_CC0_MODE TC_DRVCTRL_INVEN(1) +/** Waveform inversion CC1 mode. */ +#define TC_WAVEFORM_INVERT_CC1_MODE TC_DRVCTRL_INVEN(2) +#else +/** Waveform inversion CC0 mode. */ +#define TC_WAVEFORM_INVERT_CC0_MODE TC_CTRLC_INVEN(1) +/** Waveform inversion CC1 mode. */ +#define TC_WAVEFORM_INVERT_CC1_MODE TC_CTRLC_INVEN(2) +#endif + +/** + * \brief Waveform inversion mode. + * + * Output waveform inversion mode. + */ +enum tc_waveform_invert_output { + /** No inversion of the waveform output */ + TC_WAVEFORM_INVERT_OUTPUT_NONE = 0, + /** Invert output from compare channel 0 */ + TC_WAVEFORM_INVERT_OUTPUT_CHANNEL_0 = TC_WAVEFORM_INVERT_CC0_MODE, + /** Invert output from compare channel 1 */ + TC_WAVEFORM_INVERT_OUTPUT_CHANNEL_1 = TC_WAVEFORM_INVERT_CC1_MODE, +}; + +/** + * \brief Action to perform when the TC module is triggered by an event. + * + * Event action to perform when the module is triggered by an event. + */ +enum tc_event_action { + /** No event action */ + TC_EVENT_ACTION_OFF = TC_EVCTRL_EVACT_OFF, + /** Re-trigger on event */ + TC_EVENT_ACTION_RETRIGGER = TC_EVCTRL_EVACT_RETRIGGER, + /** Increment counter on event */ + TC_EVENT_ACTION_INCREMENT_COUNTER = TC_EVCTRL_EVACT_COUNT, + /** Start counter on event */ + TC_EVENT_ACTION_START = TC_EVCTRL_EVACT_START, + + /** Store period in capture register 0, pulse width in capture + * register 1 + */ + TC_EVENT_ACTION_PPW = TC_EVCTRL_EVACT_PPW, + + /** Store pulse width in capture register 0, period in capture + * register 1 + */ + TC_EVENT_ACTION_PWP = TC_EVCTRL_EVACT_PWP, +#ifdef FEATURE_TC_STAMP_PW_CAPTURE + /** Time stamp capture */ + TC_EVENT_ACTION_STAMP = TC_EVCTRL_EVACT_STAMP, + /** Pulse width capture */ + TC_EVENT_ACTION_PW = TC_EVCTRL_EVACT_PW, +#endif +}; + +/** + * \brief TC event enable/disable structure. + * + * Event flags for the \ref tc_enable_events() and \ref tc_disable_events(). + */ +struct tc_events { + /** Generate an output event on a compare channel match */ + bool generate_event_on_compare_channel + [NUMBER_OF_COMPARE_CAPTURE_CHANNELS]; + /** Generate an output event on counter overflow */ + bool generate_event_on_overflow; + /** Perform the configured event action when an incoming event is signalled */ + bool on_event_perform_action; + /** Specifies if the input event source is inverted, when used in PWP or + * PPW event action modes + */ + bool invert_event_input; + /** Specifies which event to trigger if an event is triggered */ + enum tc_event_action event_action; +}; + +/** + * \brief Configuration struct for TC module in 8-bit size counter mode. + */ +struct tc_8bit_config { + /** Initial timer count value */ + uint8_t value; + /** Where to count to or from depending on the direction on the counter */ + uint8_t period; + /** Value to be used for compare match on each channel */ + uint8_t compare_capture_channel[NUMBER_OF_COMPARE_CAPTURE_CHANNELS]; +}; + +/** + * \brief Configuration struct for TC module in 16-bit size counter mode. + */ +struct tc_16bit_config { + /** Initial timer count value */ + uint16_t value; + /** Value to be used for compare match on each channel */ + uint16_t compare_capture_channel[NUMBER_OF_COMPARE_CAPTURE_CHANNELS]; +}; + +/** + * \brief Configuration struct for TC module in 32-bit size counter mode. + */ +struct tc_32bit_config { + /** Initial timer count value */ + uint32_t value; + /** Value to be used for compare match on each channel */ + uint32_t compare_capture_channel[NUMBER_OF_COMPARE_CAPTURE_CHANNELS]; +}; + +/** + * \brief Configuration struct for TC module in 32-bit size counter mode. + */ +struct tc_pwm_channel { + /** When \c true, PWM output for the given channel is enabled */ + bool enabled; + /** Specifies pin output for each channel */ + uint32_t pin_out; + /** Specifies Multiplexer (MUX) setting for each output channel pin */ + uint32_t pin_mux; +}; + +/** + * \brief TC configuration structure. + * + * Configuration struct for a TC instance. This structure should be + * initialized by the \ref tc_get_config_defaults function before being + * modified by the user application. + */ +struct tc_config { + /** GCLK generator used to clock the peripheral */ + enum gclk_generator clock_source; + + /** When \c true the module is enabled during standby */ + bool run_in_standby; +#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + /** Run on demand */ + bool on_demand; +#endif + /** Specifies either 8-, 16-, or 32-bit counter size */ + enum tc_counter_size counter_size; + /** Specifies the prescaler value for GCLK_TC */ + enum tc_clock_prescaler clock_prescaler; + /** Specifies which waveform generation mode to use */ + enum tc_wave_generation wave_generation; + + /** Specifies the reload or reset time of the counter and prescaler + * resynchronization on a re-trigger event for the TC + */ + enum tc_reload_action reload_action; + + /** Specifies which channel(s) to invert the waveform on. + For SAM L21/L22/C20/C21, it's also used to invert I/O input pin. */ + uint8_t waveform_invert_output; + + /** Specifies which channel(s) to enable channel capture + * operation on + */ + bool enable_capture_on_channel[NUMBER_OF_COMPARE_CAPTURE_CHANNELS]; +#ifdef FEATURE_TC_IO_CAPTURE + /** Specifies which channel(s) to enable I/O capture + * operation on + */ + bool enable_capture_on_IO[NUMBER_OF_COMPARE_CAPTURE_CHANNELS]; +#endif + + /** When \c true, one-shot will stop the TC on next hardware or software + * re-trigger event or overflow/underflow + */ + bool oneshot; + + /** Specifies the direction for the TC to count */ + enum tc_count_direction count_direction; + + /** Specifies the PWM channel for TC */ + struct tc_pwm_channel pwm_channel[NUMBER_OF_COMPARE_CAPTURE_CHANNELS]; + + /** Access the different counter size settings through this configuration member. */ + union { + /** Struct for 8-bit specific timer configuration */ + struct tc_8bit_config counter_8_bit; + /** Struct for 16-bit specific timer configuration */ + struct tc_16bit_config counter_16_bit; + /** Struct for 32-bit specific timer configuration */ + struct tc_32bit_config counter_32_bit; + }; + +#ifdef FEATURE_TC_DOUBLE_BUFFERED + /** Set to \c true to enable double buffering write. When enabled any write + * through \ref tc_set_top_value(), \ref tc_set_compare_value() and + * will direct to the buffer register as buffered + * value, and the buffered value will be committed to effective register + * on UPDATE condition, if update is not locked. + */ + bool double_buffering_enabled; +#endif +}; + +#if TC_ASYNC == true +/** Forward Declaration for the device instance. */ +struct tc_module; + +/** Type of the callback functions. */ +typedef void (*tc_callback_t)(struct tc_module *const module); +#endif + +/** + * \brief TC software device instance structure. + * + * TC software instance structure, used to retain software state information + * of an associated hardware module instance. + * + * \note The fields of this structure should not be altered by the user + * application; they are reserved for module-internal use only. + */ +struct tc_module { +#if !defined(__DOXYGEN__) + /** Hardware module pointer of the associated Timer/Counter peripheral */ + Tc *hw; + + /** Size of the initialized Timer/Counter module configuration */ + enum tc_counter_size counter_size; +# if TC_ASYNC == true + /** Array of callbacks */ + tc_callback_t callback[TC_CALLBACK_N]; + /** Bit mask for callbacks registered */ + uint8_t register_callback_mask; + /** Bit mask for callbacks enabled */ + uint8_t enable_callback_mask; +# endif +#ifdef FEATURE_TC_DOUBLE_BUFFERED + /** Set to \c true to enable double buffering write */ + bool double_buffering_enabled; +#endif +#endif +}; + +#if !defined(__DOXYGEN__) +uint8_t _tc_get_inst_index( + Tc *const hw); +#endif + +/** + * \name Driver Initialization and Configuration + * @{ + */ + +/** + * \brief Determines if the hardware module(s) are currently synchronizing to + * the bus. + * + * Checks to see if the underlying hardware peripheral module(s) are currently + * synchronizing across multiple clock domains to the hardware bus. This + * function can be used to delay further operations on a module until such time + * that it is ready, to prevent blocking delays for synchronization in the + * user application. + * + * \param[in] module_inst Pointer to the software module instance struct + * + * \return Synchronization status of the underlying hardware module(s). + * + * \retval false If the module has completed synchronization + * \retval true If the module synchronization is ongoing + */ +static inline bool tc_is_syncing( + const struct tc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + TcCount8 *const tc_module = &(module_inst->hw->COUNT8); + +#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + return (tc_module->SYNCBUSY.reg); +#else + return (tc_module->STATUS.reg & TC_STATUS_SYNCBUSY); +#endif +} + +/** + * \brief Initializes config with predefined default values. + * + * This function will initialize a given TC configuration structure to + * a set of known default values. This function should be called on + * any new instance of the configuration structures before being + * modified by the user application. + * + * The default configuration is as follows: + * \li GCLK generator 0 (GCLK main) clock source + * \li 16-bit counter size on the counter + * \li No prescaler + * \li Normal frequency wave generation + * \li GCLK reload action + * \li Don't run in standby + * \li Don't run on demand for SAM L21/L22/C20/C21 + * \li No inversion of waveform output + * \li No capture enabled + * \li No I/O capture enabled for SAM L21/L22/C20/C21 + * \li No event input enabled + * \li Count upward + * \li Don't perform one-shot operations + * \li No event action + * \li No channel 0 PWM output + * \li No channel 1 PWM output + * \li Counter starts on 0 + * \li Capture compare channel 0 set to 0 + * \li Capture compare channel 1 set to 0 + * \li No PWM pin output enabled + * \li Pin and MUX configuration not set + * \li Double buffer disabled (if have this feature) + * + * \param[out] config Pointer to a TC module configuration structure to set + */ +static inline void tc_get_config_defaults( + struct tc_config *const config) +{ + /* Sanity check arguments */ + Assert(config); + + /* Write default config to config struct */ + config->clock_source = GCLK_GENERATOR_0; + config->counter_size = TC_COUNTER_SIZE_16BIT; + config->clock_prescaler = TC_CLOCK_PRESCALER_DIV1; + config->wave_generation = TC_WAVE_GENERATION_NORMAL_FREQ; + config->reload_action = TC_RELOAD_ACTION_GCLK; + config->run_in_standby = false; +#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + config->on_demand = false; +#endif + config->waveform_invert_output = TC_WAVEFORM_INVERT_OUTPUT_NONE; + config->enable_capture_on_channel[TC_COMPARE_CAPTURE_CHANNEL_0] = false; + config->enable_capture_on_channel[TC_COMPARE_CAPTURE_CHANNEL_1] = false; +#ifdef FEATURE_TC_IO_CAPTURE + config->enable_capture_on_IO[TC_COMPARE_CAPTURE_CHANNEL_0] = false; + config->enable_capture_on_IO[TC_COMPARE_CAPTURE_CHANNEL_1] = false; +#endif + + config->count_direction = TC_COUNT_DIRECTION_UP; + config->oneshot = false; + + config->pwm_channel[TC_COMPARE_CAPTURE_CHANNEL_0].enabled = false; + config->pwm_channel[TC_COMPARE_CAPTURE_CHANNEL_0].pin_out = 0; + config->pwm_channel[TC_COMPARE_CAPTURE_CHANNEL_0].pin_mux = 0; + + config->pwm_channel[TC_COMPARE_CAPTURE_CHANNEL_1].enabled = false; + config->pwm_channel[TC_COMPARE_CAPTURE_CHANNEL_1].pin_out = 0; + config->pwm_channel[TC_COMPARE_CAPTURE_CHANNEL_1].pin_mux = 0; + + config->counter_16_bit.value = 0x0000; + config->counter_16_bit.compare_capture_channel\ + [TC_COMPARE_CAPTURE_CHANNEL_0] = 0x0000; + config->counter_16_bit.compare_capture_channel\ + [TC_COMPARE_CAPTURE_CHANNEL_1] = 0x0000; +#ifdef FEATURE_TC_DOUBLE_BUFFERED + config->double_buffering_enabled = false; +#endif + +} + +enum status_code tc_init( + struct tc_module *const module_inst, + Tc *const hw, + const struct tc_config *const config); + +/** @} */ + +/** + * \name Event Management + * @{ + */ + +/** + * \brief Enables a TC module event input or output. + * + * Enables one or more input or output events to or from the TC module. + * See \ref tc_events for a list of events this module supports. + * + * \note Events cannot be altered while the module is enabled. + * + * \param[in] module_inst Pointer to the software module instance struct + * \param[in] events Struct containing flags of events to enable + */ +static inline void tc_enable_events( + struct tc_module *const module_inst, + struct tc_events *const events) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + Assert(events); + + Tc *const tc_module = module_inst->hw; + + uint32_t event_mask = 0; + + if (events->invert_event_input == true) { + event_mask |= TC_EVCTRL_TCINV; + } + + if (events->on_event_perform_action == true) { + event_mask |= TC_EVCTRL_TCEI; + } + + if (events->generate_event_on_overflow == true) { + event_mask |= TC_EVCTRL_OVFEO; + } + + for (uint8_t i = 0; i < NUMBER_OF_COMPARE_CAPTURE_CHANNELS; i++) { + if (events->generate_event_on_compare_channel[i] == true) { + event_mask |= (TC_EVCTRL_MCEO(1) << i); + } + } + + tc_module->COUNT8.EVCTRL.reg |= event_mask | events->event_action; +} + +/** + * \brief Disables a TC module event input or output. + * + * Disables one or more input or output events to or from the TC module. + * See \ref tc_events for a list of events this module supports. + * + * \note Events cannot be altered while the module is enabled. + * + * \param[in] module_inst Pointer to the software module instance struct + * \param[in] events Struct containing flags of events to disable + */ +static inline void tc_disable_events( + struct tc_module *const module_inst, + struct tc_events *const events) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + Assert(events); + + Tc *const tc_module = module_inst->hw; + + uint32_t event_mask = 0; + + if (events->invert_event_input == true) { + event_mask |= TC_EVCTRL_TCINV; + } + + if (events->on_event_perform_action == true) { + event_mask |= TC_EVCTRL_TCEI; + } + + if (events->generate_event_on_overflow == true) { + event_mask |= TC_EVCTRL_OVFEO; + } + + for (uint8_t i = 0; i < NUMBER_OF_COMPARE_CAPTURE_CHANNELS; i++) { + if (events->generate_event_on_compare_channel[i] == true) { + event_mask |= (TC_EVCTRL_MCEO(1) << i); + } + } + + tc_module->COUNT8.EVCTRL.reg &= ~event_mask; +} + +/** @} */ + +/** + * \name Enable/Disable/Reset + * @{ + */ + +enum status_code tc_reset( + const struct tc_module *const module_inst); + +/** + * \brief Enable the TC module. + * + * Enables a TC module that has been previously initialized. The counter will + * start when the counter is enabled. + * + * \note When the counter is configured to re-trigger on an event, the counter + * will not start until the start function is used. + * + * \param[in] module_inst Pointer to the software module instance struct + */ +static inline void tc_enable( + const struct tc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + TcCount8 *const tc_module = &(module_inst->hw->COUNT8); + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + /* Enable TC module */ + tc_module->CTRLA.reg |= TC_CTRLA_ENABLE; +} + +/** + * \brief Disables the TC module. + * + * Disables a TC module and stops the counter. + * + * \param[in] module_inst Pointer to the software module instance struct + */ +static inline void tc_disable( + const struct tc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + TcCount8 *const tc_module = &(module_inst->hw->COUNT8); + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + /* Disbale interrupt */ + tc_module->INTENCLR.reg = TC_INTENCLR_MASK; + /* Clear interrupt flag */ + tc_module->INTFLAG.reg = TC_INTFLAG_MASK; + + /* Disable TC module */ + tc_module->CTRLA.reg &= ~TC_CTRLA_ENABLE; +} + +/** @} */ + +/** + * \name Get/Set Count Value + * @{ + */ + +uint32_t tc_get_count_value( + const struct tc_module *const module_inst); + +enum status_code tc_set_count_value( + const struct tc_module *const module_inst, + const uint32_t count); + +/** @} */ + +/** + * \name Start/Stop Counter + * @{ + */ + +/** + * \brief Stops the counter. + * + * This function will stop the counter. When the counter is stopped + * the value in the count value is set to 0 if the counter was + * counting up, or maximum if the counter was counting + * down when stopped. + * + * \param[in] module_inst Pointer to the software module instance struct + */ +static inline void tc_stop_counter( + const struct tc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + TcCount8 *const tc_module = &(module_inst->hw->COUNT8); + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + /* Write command to execute */ + tc_module->CTRLBSET.reg = TC_CTRLBSET_CMD(TC_CTRLBSET_CMD_STOP_Val); +} + +/** + * \brief Starts the counter. + * + * Starts or restarts an initialized TC module's counter. + * + * \param[in] module_inst Pointer to the software module instance struct + */ +static inline void tc_start_counter( + const struct tc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + TcCount8 *const tc_module = &(module_inst->hw->COUNT8); + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + /* Make certain that there are no conflicting commands in the register */ + tc_module->CTRLBCLR.reg = TC_CTRLBCLR_CMD_NONE; + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + /* Write command to execute */ + tc_module->CTRLBSET.reg = TC_CTRLBSET_CMD(TC_CTRLBSET_CMD_RETRIGGER_Val); +} + +/** @} */ + +#ifdef FEATURE_TC_DOUBLE_BUFFERED +/** + * \name Double Buffering + * @{ + */ + +/** + * \brief Update double buffer. + * + * Update double buffer. + * + * \param[in] module_inst Pointer to the software module instance struct + */ +static inline void tc_update_double_buffer( + const struct tc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + TcCount8 *const tc_module = &(module_inst->hw->COUNT8); + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + /* Make certain that there are no conflicting commands in the register */ + tc_module->CTRLBCLR.reg = TC_CTRLBCLR_CMD_NONE; + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + /* Write command to execute */ + tc_module->CTRLBSET.reg = TC_CTRLBSET_CMD(TC_CTRLBSET_CMD_UPDATE_Val); +} +/** @} */ +#endif + +#ifdef FEATURE_TC_READ_SYNC +/** + * \name Count Read Synchronization + * @{ + */ + +/** + * \brief Read synchronization of COUNT. + * + * Read synchronization of COUNT. + * + * \param[in] module_inst Pointer to the software module instance struct + */ +static inline void tc_sync_read_count( + const struct tc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + TcCount8 *const tc_module = &(module_inst->hw->COUNT8); + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + /* Make certain that there are no conflicting commands in the register */ + tc_module->CTRLBCLR.reg = TC_CTRLBCLR_CMD_NONE; + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + /* Write command to execute */ + tc_module->CTRLBSET.reg = TC_CTRLBSET_CMD(TC_CTRLBSET_CMD_READSYNC_Val); +#if (SAMC20) || (SAMC21) || (SAML21) || (SAML22) || (SAMR30) + /* wait for the CMD bits in CTRLBSET to be cleared, meaning the CMD has been executed */ + while(tc_module->CTRLBSET.reg & TC_CTRLBSET_CMD_READSYNC); +#endif +} +/** @} */ +#endif + +#ifdef FEATURE_TC_GENERATE_DMA_TRIGGER +/** + * \name Generate TC DMA Triggers Command + * @{ + */ + +/** + * \brief TC DMA Trigger. + * + * TC DMA trigger command. + * + * \param[in] module_inst Pointer to the software module instance struct + */ +static inline void tc_dma_trigger_command( + const struct tc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + TcCount8 *const tc_module = &(module_inst->hw->COUNT8); + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + /* Make certain that there are no conflicting commands in the register */ + tc_module->CTRLBCLR.reg = TC_CTRLBCLR_CMD_NONE; + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + +#if (SAMC20) || (SAMC21) || (SAML22) || (SAML21XXXB) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + /* Write command to execute */ + tc_module->CTRLBSET.reg = TC_CTRLBSET_CMD(TC_CTRLBSET_CMD_DMAOS_Val); +#endif +} +/** @} */ +#endif + +/** + * \name Get Capture Set Compare + * @{ + */ + +uint32_t tc_get_capture_value( + const struct tc_module *const module_inst, + const enum tc_compare_capture_channel channel_index); + +enum status_code tc_set_compare_value( + const struct tc_module *const module_inst, + const enum tc_compare_capture_channel channel_index, + const uint32_t compare_value); + +/** @} */ + +/** + * \name Set Top Value + * @{ + */ + +enum status_code tc_set_top_value( + const struct tc_module *const module_inst, + const uint32_t top_value); + +/** @} */ + +/** + * \name Status Management + * @{ + */ + +/** + * \brief Retrieves the current module status. + * + * Retrieves the status of the module, giving overall state information. + * + * \param[in] module_inst Pointer to the TC software instance struct + * + * \return Bitmask of \c TC_STATUS_* flags. + * + * \retval TC_STATUS_CHANNEL_0_MATCH Timer channel 0 compare/capture match + * \retval TC_STATUS_CHANNEL_1_MATCH Timer channel 1 compare/capture match + * \retval TC_STATUS_SYNC_READY Timer read synchronization has completed + * \retval TC_STATUS_CAPTURE_OVERFLOW Timer capture data has overflowed + * \retval TC_STATUS_COUNT_OVERFLOW Timer count value has overflowed + * \retval TC_STATUS_CHN0_BUFFER_VALID Timer count channel 0 compare/capture buffer valid + * \retval TC_STATUS_CHN1_BUFFER_VALID Timer count channel 1 compare/capture buffer valid + * \retval TC_STATUS_PERIOD_BUFFER_VALID Timer count period buffer valid + */ +static inline uint32_t tc_get_status( + struct tc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + TcCount8 *const tc_module = &(module_inst->hw->COUNT8); + + uint32_t int_flags = tc_module->INTFLAG.reg; + + uint32_t status_flags = 0; + + /* Check for TC channel 0 match */ + if (int_flags & TC_INTFLAG_MC(1)) { + status_flags |= TC_STATUS_CHANNEL_0_MATCH; + } + + /* Check for TC channel 1 match */ + if (int_flags & TC_INTFLAG_MC(2)) { + status_flags |= TC_STATUS_CHANNEL_1_MATCH; + } + +#if !defined(FEATURE_TC_SYNCBUSY_SCHEME_VERSION_2) + /* Check for TC read synchronization ready */ + if (int_flags & TC_INTFLAG_SYNCRDY) { + status_flags |= TC_STATUS_SYNC_READY; + } +#endif + + /* Check for TC capture overflow */ + if (int_flags & TC_INTFLAG_ERR) { + status_flags |= TC_STATUS_CAPTURE_OVERFLOW; + } + + /* Check for TC count overflow */ + if (int_flags & TC_INTFLAG_OVF) { + status_flags |= TC_STATUS_COUNT_OVERFLOW; + } +#ifdef FEATURE_TC_DOUBLE_BUFFERED + uint8_t double_buffer_valid_status = tc_module->STATUS.reg; + + /* Check channel 0 compare or capture buffer valid */ + if (double_buffer_valid_status & TC_STATUS_CCBUFV0) { + status_flags |= TC_STATUS_CHN0_BUFFER_VALID; + } + /* Check channel 0 compare or capture buffer valid */ + if (double_buffer_valid_status & TC_STATUS_CCBUFV1) { + status_flags |= TC_STATUS_CHN1_BUFFER_VALID; + } + /* Check period buffer valid */ + if (double_buffer_valid_status & TC_STATUS_PERBUFV) { + status_flags |= TC_STATUS_PERIOD_BUFFER_VALID; + } +#endif + + return status_flags; +} + +/** + * \brief Clears a module status flag. + * + * Clears the given status flag of the module. + * + * \param[in] module_inst Pointer to the TC software instance struct + * \param[in] status_flags Bitmask of \c TC_STATUS_* flags to clear + */ +static inline void tc_clear_status( + struct tc_module *const module_inst, + const uint32_t status_flags) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + TcCount8 *const tc_module = &(module_inst->hw->COUNT8); + + uint32_t int_flags = 0; + + /* Check for TC channel 0 match */ + if (status_flags & TC_STATUS_CHANNEL_0_MATCH) { + int_flags |= TC_INTFLAG_MC(1); + } + + /* Check for TC channel 1 match */ + if (status_flags & TC_STATUS_CHANNEL_1_MATCH) { + int_flags |= TC_INTFLAG_MC(2); + } + +#if !defined(FEATURE_TC_SYNCBUSY_SCHEME_VERSION_2) + /* Check for TC read synchronization ready */ + if (status_flags & TC_STATUS_SYNC_READY) { + int_flags |= TC_INTFLAG_SYNCRDY; + } +#endif + + /* Check for TC capture overflow */ + if (status_flags & TC_STATUS_CAPTURE_OVERFLOW) { + int_flags |= TC_INTFLAG_ERR; + } + + /* Check for TC count overflow */ + if (status_flags & TC_STATUS_COUNT_OVERFLOW) { + int_flags |= TC_INTFLAG_OVF; + } + + /* Clear interrupt flag */ + tc_module->INTFLAG.reg = int_flags; +} + +/** @} */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +/** + * \page asfdoc_sam0_tc_extra Extra Information for TC Driver + * + * \section asfdoc_sam0_tc_extra_acronyms Acronyms + * The table below presents the acronyms used in this module: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
AcronymDescription
DMADirect Memory Access
TCTimer Counter
PWMPulse Width Modulation
PWPPulse Width Period
PPWPeriod Pulse Width
+ * + * + * \section asfdoc_sam0_tc_extra_dependencies Dependencies + * This driver has the following dependencies: + * + * - \ref asfdoc_sam0_system_pinmux_group "System Pin Multiplexer Driver" + * + * + * \section asfdoc_sam0_tc_extra_errata Errata + * There are no errata related to this driver. + * + * + * \section asfdoc_sam0_tc_extra_history Module History + * An overview of the module history is presented in the table below, with + * details on the enhancements and fixes made to the module since its first + * release. The current version of this corresponds to the newest version in + * the table. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Changelog
Added support for SAM D21 and do some modifications as below: + * \li Clean up in the configuration structure, the counter size + * setting specific registers is accessed through the counter_8_bit, + * counter_16_bit, and counter_32_bit structures + * \li All event related settings moved into the tc_event structure
Added automatic digital clock interface enable for the slave TC + * module when a timer is initialized in 32-bit mode
Initial release
+ */ + +/** + * \page asfdoc_sam0_tc_exqsg Examples for TC Driver + * + * This is a list of the available Quick Start guides (QSGs) and example + * applications for \ref asfdoc_sam0_tc_group. QSGs are simple examples with + * step-by-step instructions to configure and use this driver in a selection of + * use cases. Note that QSGs can be compiled as a standalone application or be + * added to the user application. + * + * - \subpage asfdoc_sam0_tc_basic_use_case + * - \subpage asfdoc_sam0_tc_macth_freq_use_case + * \if TC_CALLBACK_MODE + * - \subpage asfdoc_sam0_tc_timer_use_case + * - \subpage asfdoc_sam0_tc_callback_use_case + * \endif + * - \subpage asfdoc_sam0_tc_dma_use_case + * + * \page asfdoc_sam0_tc_document_revision_history Document Revision History + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Doc. Rev. + * Date + * Comments + *
42123E12/2015Added support for SAM L21/L22, SAM DA1, SAM D09, and SAM C21
42123D12/2014Added timer use case. + * Added support for SAM R21 and SAM D10/D11
42123C01/2014Added support for SAM D21
42123B06/2013Corrected documentation typos
42123A06/2013Initial document release
+ */ + +#endif /* TC_H_INCLUDED */ diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/tc/tc_interrupt.c b/src/boards/mcu/samr34/ASF/sam0/drivers/tc/tc_interrupt.c new file mode 100644 index 000000000..6d845159f --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/tc/tc_interrupt.c @@ -0,0 +1,189 @@ +/** + * \file + * + * \brief SAM TC - Timer Counter Callback Driver + * + * Copyright (c) 2013-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ + +/* + * Support and FAQ: visit Microchip Support + */ + +#include "tc_interrupt.h" + +void *_tc_instances[TC_INST_NUM]; + +void _tc_interrupt_handler(uint8_t instance); + +/** + * \brief Registers a callback. + * + * Registers a callback function which is implemented by the user. + * + * \note The callback must be enabled by \ref tc_enable_callback, + * in order for the interrupt handler to call it when the conditions for the + * callback type is met. + * + * \param[in] module Pointer to TC software instance struct + * \param[in] callback_func Pointer to callback function + * \param[in] callback_type Callback type given by an enum + */ +enum status_code tc_register_callback( + struct tc_module *const module, + tc_callback_t callback_func, + const enum tc_callback callback_type) +{ + /* Sanity check arguments */ + Assert(module); + Assert(callback_func); + + /* Register callback function */ + module->callback[callback_type] = callback_func; + + /* Set the bit corresponding to the callback_type */ + if (callback_type == TC_CALLBACK_CC_CHANNEL0) { + module->register_callback_mask |= TC_INTFLAG_MC(1); + } + else if (callback_type == TC_CALLBACK_CC_CHANNEL1) { + module->register_callback_mask |= TC_INTFLAG_MC(2); + } + else { + module->register_callback_mask |= (1 << callback_type); + } + return STATUS_OK; +} + +/** + * \brief Unregisters a callback. + * + * Unregisters a callback function implemented by the user. The callback should be + * disabled before it is unregistered. + * + * \param[in] module Pointer to TC software instance struct + * \param[in] callback_type Callback type given by an enum + */ +enum status_code tc_unregister_callback( + struct tc_module *const module, + const enum tc_callback callback_type) +{ + /* Sanity check arguments */ + Assert(module); + + /* Unregister callback function */ + module->callback[callback_type] = NULL; + + /* Clear the bit corresponding to the callback_type */ + if (callback_type == TC_CALLBACK_CC_CHANNEL0) { + module->register_callback_mask &= ~TC_INTFLAG_MC(1); + } + else if (callback_type == TC_CALLBACK_CC_CHANNEL1) { + module->register_callback_mask &= ~TC_INTFLAG_MC(2); + } + else { + module->register_callback_mask &= ~(1 << callback_type); + } + return STATUS_OK; +} + +/** + * \internal ISR handler for TC + * + * Auto-generate a set of interrupt handlers for each TC in the device. + */ +#define _TC_INTERRUPT_HANDLER(n, m) \ + void TC##n##_Handler(void) \ + { \ + _tc_interrupt_handler(m); \ + } + +#if (SAML21E) || (SAML21G) || (SAMR30E) || (SAMR30G) + _TC_INTERRUPT_HANDLER(0,0) + _TC_INTERRUPT_HANDLER(1,1) + _TC_INTERRUPT_HANDLER(4,2) +#else + MRECURSION(TC_INST_NUM, _TC_INTERRUPT_HANDLER, TC_INST_MAX_ID) +#endif + + +/** + * \internal Interrupt Handler for TC module + * + * Handles interrupts as they occur, it will run the callback functions + * that are registered and enabled. + * + * \param[in] instance ID of the TC instance calling the interrupt + * handler + */ +void _tc_interrupt_handler( + uint8_t instance) +{ + /* Temporary variable */ + uint8_t interrupt_and_callback_status_mask; + + /* Get device instance from the look-up table */ + struct tc_module *module + = (struct tc_module *)_tc_instances[instance]; + + /* Read and mask interrupt flag register */ + interrupt_and_callback_status_mask = module->hw->COUNT8.INTFLAG.reg & + module->register_callback_mask & + module->enable_callback_mask; + + /* Check if an Overflow interrupt has occurred */ + if (interrupt_and_callback_status_mask & TC_INTFLAG_OVF) { + /* Invoke registered and enabled callback function */ + (module->callback[TC_CALLBACK_OVERFLOW])(module); + /* Clear interrupt flag */ + module->hw->COUNT8.INTFLAG.reg = TC_INTFLAG_OVF; + } + + /* Check if an Error interrupt has occurred */ + if (interrupt_and_callback_status_mask & TC_INTFLAG_ERR) { + /* Invoke registered and enabled callback function */ + (module->callback[TC_CALLBACK_ERROR])(module); + /* Clear interrupt flag */ + module->hw->COUNT8.INTFLAG.reg = TC_INTFLAG_ERR; + } + + /* Check if an Match/Capture Channel 0 interrupt has occurred */ + if (interrupt_and_callback_status_mask & TC_INTFLAG_MC(1)) { + /* Invoke registered and enabled callback function */ + (module->callback[TC_CALLBACK_CC_CHANNEL0])(module); + /* Clear interrupt flag */ + module->hw->COUNT8.INTFLAG.reg = TC_INTFLAG_MC(1); + } + + /* Check if an Match/Capture Channel 1 interrupt has occurred */ + if (interrupt_and_callback_status_mask & TC_INTFLAG_MC(2)) { + /* Invoke registered and enabled callback function */ + (module->callback[TC_CALLBACK_CC_CHANNEL1])(module); + /* Clear interrupt flag */ + module->hw->COUNT8.INTFLAG.reg = TC_INTFLAG_MC(2); + } +} diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/tc/tc_interrupt.h b/src/boards/mcu/samr34/ASF/sam0/drivers/tc/tc_interrupt.h new file mode 100644 index 000000000..9329e0928 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/tc/tc_interrupt.h @@ -0,0 +1,169 @@ +/** + * \file + * + * \brief SAM TC - Timer Counter Callback Driver + * + * Copyright (c) 2013-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ + +/* + * Support and FAQ: visit Microchip Support + */ + +#ifndef TC_INTERRUPT_H_INCLUDED +#define TC_INTERRUPT_H_INCLUDED + +#include "tc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(__DOXYGEN__) +extern void *_tc_instances[TC_INST_NUM]; + +# define _TC_INTERRUPT_VECT_NUM(n, unused) \ + SYSTEM_INTERRUPT_MODULE_TC##n, +/** + * \internal Get the interrupt vector for the given device instance + * + * \param[in] TC module instance number + * + * \return Interrupt vector for of the given TC module instance. + */ +static enum system_interrupt_vector _tc_interrupt_get_interrupt_vector( + uint32_t inst_num) +{ + static uint8_t tc_interrupt_vectors[TC_INST_NUM] = + { +#if (SAML21E) || (SAML21G) || (SAMR30E) || (SAMR30G) + SYSTEM_INTERRUPT_MODULE_TC0, + SYSTEM_INTERRUPT_MODULE_TC1, + SYSTEM_INTERRUPT_MODULE_TC4 +#else + MRECURSION(TC_INST_NUM, _TC_INTERRUPT_VECT_NUM, TC_INST_MAX_ID) +#endif + }; + + return (enum system_interrupt_vector)tc_interrupt_vectors[inst_num]; +} +#endif /* !defined(__DOXYGEN__) */ + +/** + * \name Callback Management + * {@ + */ + +enum status_code tc_register_callback( + struct tc_module *const module, + tc_callback_t callback_func, + const enum tc_callback callback_type); + +enum status_code tc_unregister_callback( + struct tc_module *const module, + const enum tc_callback callback_type); + +/** + * \brief Enables callback. + * + * Enables the callback function registered by the \ref + * tc_register_callback. The callback function will be called from the + * interrupt handler when the conditions for the callback type are + * met. This function will also enable the appropriate interrupts. + * + * \param[in] module Pointer to TC software instance struct + * \param[in] callback_type Callback type given by an enum + */ +static inline void tc_enable_callback( + struct tc_module *const module, + const enum tc_callback callback_type) +{ + /* Sanity check arguments */ + Assert(module); + + + /* Enable interrupts for this TC module */ + system_interrupt_enable(_tc_interrupt_get_interrupt_vector(_tc_get_inst_index(module->hw))); + + /* Enable callback */ + if (callback_type == TC_CALLBACK_CC_CHANNEL0) { + module->enable_callback_mask |= TC_INTFLAG_MC(1); + module->hw->COUNT8.INTENSET.reg = TC_INTFLAG_MC(1); + } + else if (callback_type == TC_CALLBACK_CC_CHANNEL1) { + module->enable_callback_mask |= TC_INTFLAG_MC(2); + module->hw->COUNT8.INTENSET.reg = TC_INTFLAG_MC(2); + } + else { + module->enable_callback_mask |= (1 << callback_type); + module->hw->COUNT8.INTENSET.reg = (1 << callback_type); + } +} + +/** + * \brief Disables callback. + * + * Disables the callback function registered by the \ref + * tc_register_callback, and the callback will not be called from the + * interrupt routine. The function will also disable the appropriate + * interrupts. + * + * \param[in] module Pointer to TC software instance struct + * \param[in] callback_type Callback type given by an enum + */ +static inline void tc_disable_callback( + struct tc_module *const module, + const enum tc_callback callback_type){ + /* Sanity check arguments */ + Assert(module); + + /* Disable callback */ + if (callback_type == TC_CALLBACK_CC_CHANNEL0) { + module->hw->COUNT8.INTENCLR.reg = TC_INTFLAG_MC(1); + module->enable_callback_mask &= ~TC_INTFLAG_MC(1); + } + else if (callback_type == TC_CALLBACK_CC_CHANNEL1) { + module->hw->COUNT8.INTENCLR.reg = TC_INTFLAG_MC(2); + module->enable_callback_mask &= ~TC_INTFLAG_MC(2); + } + else { + module->hw->COUNT8.INTENCLR.reg = (1 << callback_type); + module->enable_callback_mask &= ~(1 << callback_type); + } +} + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* TC_INTERRUPT_H_INCLUDED */ diff --git a/src/boards/mcu/samr34/ASF/sam0/drivers/tc/tc_sam_l_c/tc.c b/src/boards/mcu/samr34/ASF/sam0/drivers/tc/tc_sam_l_c/tc.c new file mode 100644 index 000000000..f42aee2e2 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/drivers/tc/tc_sam_l_c/tc.c @@ -0,0 +1,713 @@ +/** + * \file + * + * \brief SAM TC - Timer Counter Driver + * + * Copyright (c) 2014-2020 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#include "tc.h" + +#if TC_ASYNC == true +# include "tc_interrupt.h" +# include +#endif + +/** + * \internal Find the index of given TC module instance. + * + * \param[in] TC module instance pointer + * + * \return Index of the given TC module instance. + */ +uint8_t _tc_get_inst_index( + Tc *const hw) +{ + /* List of available TC modules. */ + Tc *const tc_modules[TC_INST_NUM] = TC_INSTS; + + /* Find index for TC instance. */ + for (uint32_t i = 0; i < TC_INST_NUM; i++) { + if (hw == tc_modules[i]) { + return i; + } + } + + /* Invalid data given. */ + Assert(false); + return 0; +} + + +/** + * \brief Initializes a hardware TC module instance. + * + * Enables the clock and initializes the TC module, based on the given + * configuration values. + * + * \param[in,out] module_inst Pointer to the software module instance struct + * \param[in] hw Pointer to the TC hardware module + * \param[in] config Pointer to the TC configuration options struct + * + * \return Status of the initialization procedure. + * + * \retval STATUS_OK The module was initialized successfully + * \retval STATUS_BUSY Hardware module was busy when the + * initialization procedure was attempted + * \retval STATUS_INVALID_ARG An invalid configuration option or argument + * was supplied + * \retval STATUS_ERR_DENIED Hardware module was already enabled, or the + * hardware module is configured in 32-bit + * slave mode + */ +enum status_code tc_init( + struct tc_module *const module_inst, + Tc *const hw, + const struct tc_config *const config) +{ + /* Sanity check arguments */ + Assert(hw); + Assert(module_inst); + Assert(config); + + /* Temporary variable to hold all updates to the CTRLA + * register before they are written to it */ + uint32_t ctrla_tmp = 0; + /* Temporary variable to hold all updates to the CTRLBSET + * register before they are written to it */ + uint8_t ctrlbset_tmp = 0; + /* Temporary variable to hold TC instance number */ + uint8_t instance = _tc_get_inst_index(hw); + +#if (SAMC20) || (SAMC21) + /* Array of GLCK ID for different TC instances */ + uint8_t inst_gclk_id[] = {TC0_GCLK_ID, TC1_GCLK_ID, TC2_GCLK_ID, TC3_GCLK_ID, TC4_GCLK_ID}; + /* Array of MCLK APB mask bit position for different TC instances */ + uint32_t inst_mclk_apbmask[] = {SYSTEM_CLOCK_APB_APBC, MCLK_APBCMASK_TC0, + SYSTEM_CLOCK_APB_APBC, MCLK_APBCMASK_TC1, + SYSTEM_CLOCK_APB_APBC, MCLK_APBCMASK_TC2, + SYSTEM_CLOCK_APB_APBC, MCLK_APBCMASK_TC3, + SYSTEM_CLOCK_APB_APBC, MCLK_APBCMASK_TC4}; +#elif (SAML21J) || (SAMR34J) || (SAMR35J) || (WLR089U0) + /* Array of GLCK ID for different TC instances */ + uint8_t inst_gclk_id[] = {TC0_GCLK_ID, TC1_GCLK_ID, TC2_GCLK_ID, TC3_GCLK_ID, TC4_GCLK_ID}; + /* Array of MCLK APB mask bit position for different TC instances */ + uint32_t inst_mclk_apbmask[] = {SYSTEM_CLOCK_APB_APBC, MCLK_APBCMASK_TC0, + SYSTEM_CLOCK_APB_APBC, MCLK_APBCMASK_TC1, + SYSTEM_CLOCK_APB_APBC, MCLK_APBCMASK_TC2, + SYSTEM_CLOCK_APB_APBC, MCLK_APBCMASK_TC3, + SYSTEM_CLOCK_APB_APBD, MCLK_APBDMASK_TC4}; +#elif (SAML22) + /* Array of GLCK ID for different TC instances */ + uint8_t inst_gclk_id[] = {TC0_GCLK_ID, TC1_GCLK_ID, TC2_GCLK_ID, TC3_GCLK_ID}; + /* Array of MCLK APB mask bit position for different TC instances */ + uint32_t inst_mclk_apbmask[] = {SYSTEM_CLOCK_APB_APBC, MCLK_APBCMASK_TC0, + SYSTEM_CLOCK_APB_APBC, MCLK_APBCMASK_TC1, + SYSTEM_CLOCK_APB_APBC, MCLK_APBCMASK_TC2, + SYSTEM_CLOCK_APB_APBC, MCLK_APBCMASK_TC3}; +#else + /* Array of GLCK ID for different TC instances */ + uint8_t inst_gclk_id[] = {TC0_GCLK_ID, TC1_GCLK_ID, TC4_GCLK_ID}; + /* Array of PM APB mask bit position for different TC instances */ + uint32_t inst_mclk_apbmask[] = {SYSTEM_CLOCK_APB_APBC, MCLK_APBCMASK_TC0, + SYSTEM_CLOCK_APB_APBC, MCLK_APBCMASK_TC1, + SYSTEM_CLOCK_APB_APBD, MCLK_APBDMASK_TC4}; +#endif + + struct system_pinmux_config pin_config; + struct system_gclk_chan_config gclk_chan_config; + +#if TC_ASYNC == true + /* Initialize parameters */ + for (uint8_t i = 0; i < TC_CALLBACK_N; i++) { + module_inst->callback[i] = NULL; + } + module_inst->register_callback_mask = 0x00; + module_inst->enable_callback_mask = 0x00; + + /* Register this instance for callbacks*/ + _tc_instances[instance] = module_inst; +#endif + + /* Associate the given device instance with the hardware module */ + module_inst->hw = hw; + + module_inst->double_buffering_enabled = config->double_buffering_enabled; + + /* Check if odd numbered TC modules are being configured in 32-bit + * counter size. Only even numbered counters are allowed to be + * configured in 32-bit counter size. + */ + if ((config->counter_size == TC_COUNTER_SIZE_32BIT) && + ((instance + TC_INSTANCE_OFFSET) & 0x01)) { + Assert(false); + return STATUS_ERR_INVALID_ARG; + } + + /* Make the counter size variable in the module_inst struct reflect + * the counter size in the module + */ + module_inst->counter_size = config->counter_size; + + if (hw->COUNT8.CTRLA.reg & TC_CTRLA_SWRST) { + /* We are in the middle of a reset. Abort. */ + return STATUS_BUSY; + } + + if (hw->COUNT8.STATUS.reg & TC_STATUS_SLAVE) { + /* Module is used as a slave */ + return STATUS_ERR_DENIED; + } + + if (hw->COUNT8.CTRLA.reg & TC_CTRLA_ENABLE) { + /* Module must be disabled before initialization. Abort. */ + return STATUS_ERR_DENIED; + } + + /* Set up the TC PWM out pin for channel 0 */ + if (config->pwm_channel[0].enabled) { + system_pinmux_get_config_defaults(&pin_config); + pin_config.mux_position = config->pwm_channel[0].pin_mux; + pin_config.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT; + system_pinmux_pin_set_config( + config->pwm_channel[0].pin_out, &pin_config); + } + + /* Set up the TC PWM out pin for channel 1 */ + if (config->pwm_channel[1].enabled) { + system_pinmux_get_config_defaults(&pin_config); + pin_config.mux_position = config->pwm_channel[1].pin_mux; + pin_config.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT; + system_pinmux_pin_set_config( + config->pwm_channel[1].pin_out, &pin_config); + } + + /* Enable the user interface clock in the MCLK */ + system_apb_clock_set_mask((enum system_clock_apb_bus)inst_mclk_apbmask[instance*2], + inst_mclk_apbmask[2*instance+1]); + + /* Enable the slave counter if counter_size is 32-bit */ + if ((config->counter_size == TC_COUNTER_SIZE_32BIT) && (instance+1 < TC_INST_NUM)) + { + /* Enable the user interface clock in the MCLK */ + system_apb_clock_set_mask((enum system_clock_apb_bus)inst_mclk_apbmask[(instance+1)*2], + inst_mclk_apbmask[(instance+1)*2+1]); + } + + + /* Setup clock for module */ + system_gclk_chan_get_config_defaults(&gclk_chan_config); + gclk_chan_config.source_generator = config->clock_source; + system_gclk_chan_set_config(inst_gclk_id[instance], &gclk_chan_config); + system_gclk_chan_enable(inst_gclk_id[instance]); + + /* Set ctrla register */ + ctrla_tmp = + (uint32_t)config->counter_size | + (uint32_t)config->reload_action | + (uint32_t)config->clock_prescaler; + + for (uint8_t i = 0; i < NUMBER_OF_COMPARE_CAPTURE_CHANNELS; i++) { + if (config->enable_capture_on_channel[i] == true) { + ctrla_tmp |= (TC_CTRLA_CAPTEN(1) << i); + } + } + + for (uint8_t i = 0; i < NUMBER_OF_COMPARE_CAPTURE_CHANNELS; i++) { + if (config->enable_capture_on_IO[i] == true) { + ctrla_tmp |= (TC_CTRLA_COPEN(1) << i); + } + } + + ctrla_tmp |= (config->run_in_standby << TC_CTRLA_RUNSTDBY_Pos) + |(config->on_demand << TC_CTRLA_ONDEMAND_Pos); + + /* Write configuration to register */ + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + hw->COUNT8.CTRLA.reg = ctrla_tmp; + + /* Write configuration to register */ + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + hw->COUNT8.WAVE.reg = config->wave_generation; + + /* Set ctrlb register */ + if (config->oneshot) { + ctrlbset_tmp = TC_CTRLBSET_ONESHOT; + } + + if (config->count_direction) { + ctrlbset_tmp |= TC_CTRLBSET_DIR; + } + + /* Clear old ctrlb configuration */ + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + hw->COUNT8.CTRLBCLR.reg = 0xFF; + + /* Check if we actually need to go into a wait state. */ + if (ctrlbset_tmp) { + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + /* Write configuration to register */ + hw->COUNT8.CTRLBSET.reg = ctrlbset_tmp; + } + + /* Set drvvtrl register*/ + hw->COUNT8.DRVCTRL.reg = config->waveform_invert_output; + + /* Write configuration to register */ + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + /* Switch for TC counter size */ + switch (module_inst->counter_size) { + case TC_COUNTER_SIZE_8BIT: + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + hw->COUNT8.COUNT.reg = + config->counter_8_bit.value; + + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + hw->COUNT8.PER.reg = + config->counter_8_bit.period; + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + hw->COUNT8.CC[0].reg = + config->counter_8_bit.compare_capture_channel[0]; + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + hw->COUNT8.CC[1].reg = + config->counter_8_bit.compare_capture_channel[1]; + + return STATUS_OK; + + case TC_COUNTER_SIZE_16BIT: + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + hw->COUNT16.COUNT.reg + = config->counter_16_bit.value; + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + hw->COUNT16.CC[0].reg = + config->counter_16_bit.compare_capture_channel[0]; + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + hw->COUNT16.CC[1].reg = + config->counter_16_bit.compare_capture_channel[1]; + + return STATUS_OK; + + case TC_COUNTER_SIZE_32BIT: + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + hw->COUNT32.COUNT.reg + = config->counter_32_bit.value; + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + hw->COUNT32.CC[0].reg = + config->counter_32_bit.compare_capture_channel[0]; + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + hw->COUNT32.CC[1].reg = + config->counter_32_bit.compare_capture_channel[1]; + + return STATUS_OK; + } + + Assert(false); + return STATUS_ERR_INVALID_ARG; +} + +/** + * \brief Sets TC module count value. + * + * Sets the current timer count value of a initialized TC module. The + * specified TC module may be started or stopped. + * + * \param[in] module_inst Pointer to the software module instance struct + * \param[in] count New timer count value to set + * + * \return Status of the count update procedure. + * + * \retval STATUS_OK The timer count was updated successfully + * \retval STATUS_ERR_INVALID_ARG An invalid timer counter size was specified + */ +enum status_code tc_set_count_value( + const struct tc_module *const module_inst, + const uint32_t count) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance*/ + Tc *const tc_module = module_inst->hw; + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + /* Write to based on the TC counter_size */ + switch (module_inst->counter_size) { + case TC_COUNTER_SIZE_8BIT: + tc_module->COUNT8.COUNT.reg = (uint8_t)count; + return STATUS_OK; + + case TC_COUNTER_SIZE_16BIT: + tc_module->COUNT16.COUNT.reg = (uint16_t)count; + return STATUS_OK; + + case TC_COUNTER_SIZE_32BIT: + tc_module->COUNT32.COUNT.reg = (uint32_t)count; + return STATUS_OK; + + default: + return STATUS_ERR_INVALID_ARG; + } +} + +/** + * \brief Get TC module count value. + * + * Retrieves the current count value of a TC module. The specified TC module + * may be started or stopped. + * + * \param[in] module_inst Pointer to the software module instance struct + * + * \return Count value of the specified TC module. + */ +uint32_t tc_get_count_value( + const struct tc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Read synchronization */ + tc_sync_read_count(module_inst); + + /* Get a pointer to the module's hardware instance */ + Tc *const tc_module = module_inst->hw; + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + /* Read from based on the TC counter size */ + switch (module_inst->counter_size) { + case TC_COUNTER_SIZE_8BIT: + return (uint32_t)tc_module->COUNT8.COUNT.reg; + + case TC_COUNTER_SIZE_16BIT: + return (uint32_t)tc_module->COUNT16.COUNT.reg; + + case TC_COUNTER_SIZE_32BIT: + return tc_module->COUNT32.COUNT.reg; + } + + Assert(false); + return 0; +} + +/** + * \brief Gets the TC module capture value. + * + * Retrieves the capture value in the indicated TC module capture channel. + * + * \param[in] module_inst Pointer to the software module instance struct + * \param[in] channel_index Index of the Compare Capture channel to read + * + * \return Capture value stored in the specified timer channel. + */ +uint32_t tc_get_capture_value( + const struct tc_module *const module_inst, + const enum tc_compare_capture_channel channel_index) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + Tc *const tc_module = module_inst->hw; + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + /* Read out based on the TC counter size */ + switch (module_inst->counter_size) { + case TC_COUNTER_SIZE_8BIT: + if (channel_index < + NUMBER_OF_COMPARE_CAPTURE_CHANNELS) { + return tc_module->COUNT8.CC[channel_index].reg; + } + + case TC_COUNTER_SIZE_16BIT: + if (channel_index < + NUMBER_OF_COMPARE_CAPTURE_CHANNELS) { + return tc_module->COUNT16.CC[channel_index].reg; + } + + case TC_COUNTER_SIZE_32BIT: + if (channel_index < + NUMBER_OF_COMPARE_CAPTURE_CHANNELS) { + return tc_module->COUNT32.CC[channel_index].reg; + } + } + + Assert(false); + return 0; +} + +/** + * \brief Sets a TC module compare value. + * + * Writes a compare value to the given TC module compare/capture channel. + * + * \param[in] module_inst Pointer to the software module instance struct + * \param[in] channel_index Index of the compare channel to write to + * \param[in] compare New compare value to set + * + * \return Status of the compare update procedure. + * + * \retval STATUS_OK The compare value was updated successfully + * \retval STATUS_ERR_INVALID_ARG An invalid channel index was supplied + */ +enum status_code tc_set_compare_value( + const struct tc_module *const module_inst, + const enum tc_compare_capture_channel channel_index, + const uint32_t compare) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + Assert(compare); + + /* Get a pointer to the module's hardware instance */ + Tc *const tc_module = module_inst->hw; + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + /* Read out based on the TC counter size */ + switch (module_inst->counter_size) { + case TC_COUNTER_SIZE_8BIT: + if (channel_index < + NUMBER_OF_COMPARE_CAPTURE_CHANNELS) { + if (module_inst->double_buffering_enabled){ + tc_module->COUNT8.CCBUF[channel_index].reg = + (uint8_t)compare; + } else { + tc_module->COUNT8.CC[channel_index].reg = + (uint8_t)compare; + } + return STATUS_OK; + } + case TC_COUNTER_SIZE_16BIT: + if (channel_index < + NUMBER_OF_COMPARE_CAPTURE_CHANNELS) { + if (module_inst->double_buffering_enabled){ + tc_module->COUNT16.CCBUF[channel_index].reg = + (uint16_t)compare; + } else { + tc_module->COUNT16.CC[channel_index].reg = + (uint16_t)compare; + } + return STATUS_OK; + } + + case TC_COUNTER_SIZE_32BIT: + if (channel_index < + NUMBER_OF_COMPARE_CAPTURE_CHANNELS) { + if (module_inst->double_buffering_enabled){ + tc_module->COUNT32.CCBUF[channel_index].reg = + (uint32_t)compare; + } else { + tc_module->COUNT32.CC[channel_index].reg = + (uint32_t)compare; + } + return STATUS_OK; + } + } + + return STATUS_ERR_INVALID_ARG; +} + +/** + * \brief Resets the TC module. + * + * Resets the TC module, restoring all hardware module registers to their + * default values and disabling the module. The TC module will not be + * accessible while the reset is being performed. + * + * \note When resetting a 32-bit counter only the master TC module's instance + * structure should be passed to the function. + * + * \param[in] module_inst Pointer to the software module instance struct + * + * \return Status of the procedure. + * \retval STATUS_OK The module was reset successfully + * \retval STATUS_ERR_UNSUPPORTED_DEV A 32-bit slave TC module was passed to + * the function. Only use reset on master + * TC + */ +enum status_code tc_reset( + const struct tc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module hardware instance */ + TcCount8 *const tc_module = &(module_inst->hw->COUNT8); + + if (tc_module->STATUS.reg & TC_STATUS_SLAVE) { + return STATUS_ERR_UNSUPPORTED_DEV; + } + + /* Disable this module if it is running */ + if (tc_module->CTRLA.reg & TC_CTRLA_ENABLE) { + tc_disable(module_inst); + while (tc_is_syncing(module_inst)) { + /* wait while module is disabling */ + } + } + + /* Reset this TC module */ + tc_module->CTRLA.reg |= TC_CTRLA_SWRST; + + return STATUS_OK; +} + +/** + * \brief Set the timer TOP/period value. + * + * For 8-bit counter size this function writes the top value to the period + * register. + * + * For 16- and 32-bit counter size this function writes the top value to + * Capture Compare register 0. The value in this register can not be used for + * any other purpose. + * + * \note This function is designed to be used in PWM or frequency + * match modes only, when the counter is set to 16- or 32-bit counter + * size. In 8-bit counter size it will always be possible to change the + * top value even in normal mode. + * + * \param[in] module_inst Pointer to the software module instance struct + * \param[in] top_value New timer TOP value to set + * + * \return Status of the TOP set procedure. + * + * \retval STATUS_OK The timer TOP value was updated successfully + * \retval STATUS_ERR_INVALID_ARG The configured TC module counter size in the + * module instance is invalid + */ +enum status_code tc_set_top_value ( + const struct tc_module *const module_inst, + const uint32_t top_value) +{ + Assert(module_inst); + Assert(module_inst->hw); + Assert(top_value); + + Tc *const tc_module = module_inst->hw; + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + switch (module_inst->counter_size) { + case TC_COUNTER_SIZE_8BIT: + if (module_inst->double_buffering_enabled){ + tc_module->COUNT8.PERBUF.reg = (uint8_t)top_value; + } else { + tc_module->COUNT8.PER.reg = (uint8_t)top_value; + } + return STATUS_OK; + + case TC_COUNTER_SIZE_16BIT: + if (module_inst->double_buffering_enabled){ + tc_module->COUNT16.CCBUF[0].reg = (uint16_t)top_value; + } else { + tc_module->COUNT16.CC[0].reg = (uint16_t)top_value; + } + return STATUS_OK; + + case TC_COUNTER_SIZE_32BIT: + if (module_inst->double_buffering_enabled){ + tc_module->COUNT32.CCBUF[0].reg = (uint32_t)top_value; + } else { + tc_module->COUNT32.CC[0].reg = (uint32_t)top_value; + } + return STATUS_OK; + + default: + Assert(false); + return STATUS_ERR_INVALID_ARG; + } +} diff --git a/src/boards/mcu/samr34/ASF/sam0/services/eeprom/emulator/rwwee_array/quick_start/qs_emulator_basic.h b/src/boards/mcu/samr34/ASF/sam0/services/eeprom/emulator/rwwee_array/quick_start/qs_emulator_basic.h new file mode 100644 index 000000000..17685476f --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/services/eeprom/emulator/rwwee_array/quick_start/qs_emulator_basic.h @@ -0,0 +1,94 @@ +/** + * \file + * + * \brief SAM RWW EEPROM Emulator Service Quick Start + * + * Copyright (c) 2014-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ + +/** + * \page asfdoc_sam0_rww_eeprom_basic_use_case Quick Start Guide for the Emulated RWW EEPROM Module - Basic Use Case + * + * In this use case, the RWW EEPROM emulator module is configured, and a sample page + * is read and written. The first byte of the first RWW EEPROM page is toggled, + * and a LED is turned ON or OFF to reflect the new state. Each time the device + * is reset, the LED should toggle to a different state to indicate correct + * non-volatile storage and retrieval. + * + * + * \section asfdoc_sam0_rww_eeprom_basic_use_case_setup Setup + * + * \subsection asfdoc_sam0_rww_eeprom_basic_use_case_setup_prereq Prerequisites + * There are no special setup requirements for this use-case. + * + * \subsection asfdoc_sam0_rww_eeprom_basic_use_case_setup_code Code + * Copy-paste the following setup code to your user application: + * \snippet qs_emulator_basic.c setup + * + * Add to user application initialization (typically the start of \c main()): + * \snippet qs_emulator_basic.c setup_init + * + * \subsection asfdoc_sam0_rww_eeprom_basic_use_case_setup_flow Workflow + * -# Attempt to initialize the RWW EEPROM emulator service, storing the error code + * from the initialization function into a temporary variable. + * \snippet qs_emulator_basic.c init_eeprom_service + * -# Check if the emulator service failed to initialize for any other reason; + * if so, assume the emulator physical memory is unformatted or corrupt and + * erase/re-try initialization. + * \snippet qs_emulator_basic.c check_re-init + * + * Config BOD to give an early warning to prevent data loss. + * \snippet qs_emulator_basic.c setup_bod + * + * \section asfdoc_sam0_rww_eeprom_basic_use_case_main Use Case + * + * \subsection asfdoc_sam0_rww_eeprom_basic_use_case_main_code Code + * Copy-paste the following code to your user application: + * \snippet qs_emulator_basic.c main + * + * \subsection asfdoc_sam0_rww_eeprom_basic_use_case_main_flow Workflow + * -# Create a buffer to hold a single emulated RWW EEPROM page of memory, and read + * out logical RWW EEPROM page zero into it. + * \snippet qs_emulator_basic.c read_page + * -# Toggle the first byte of the read page. + * \snippet qs_emulator_basic.c toggle_first_byte + * -# Output the toggled LED state onto the board LED. + * \snippet qs_emulator_basic.c set_led + * -# Write the modified page back to logical RWW EEPROM page zero, flushing the + * internal emulator write cache afterwards to ensure it is immediately + * written to physical non-volatile memory. + * \snippet qs_emulator_basic.c write_page + * -# Modify data and write back to logical EEPROM page zero. + * The data is not committed and should call \c rww_eeprom_emulator_commit_page_buffer + * to ensure that any outstanding cache data is fully written to prevent data loss + * when detecting a BOD early warning. + * \snippet qs_emulator_basic.c write_page_not_commit + */ +/* + * Support and FAQ: visit Microchip Support + */ diff --git a/src/boards/mcu/samr34/ASF/sam0/services/eeprom/emulator/rwwee_array/rww_eeprom.c b/src/boards/mcu/samr34/ASF/sam0/services/eeprom/emulator/rwwee_array/rww_eeprom.c new file mode 100644 index 000000000..baf30fc29 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/services/eeprom/emulator/rwwee_array/rww_eeprom.c @@ -0,0 +1,1136 @@ +/** + * \file + * + * \brief SAM Read While Write EEPROM Emulator + * + * Copyright (c) 2014-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#include "rww_eeprom.h" +#include +#include +#include "conf_rwwee.h" + +#if !defined(CONF_LOGICAL_PAGE_NUM_IN_ROW) || defined(__DOXYGEN__) +# warning CONF_LOGICAL_PAGE_NUM_IN_ROW is not defined, assuming RWWEE_LOGICAL_PAGE_NUM_1. + +/** Configuration option, one logical page stored in a physical row. + */ +# define CONF_LOGICAL_PAGE_NUM_IN_ROW RWWEE_LOGICAL_PAGE_NUM_1 +#endif + +#if !defined(CONF_PAGE_CHECKSUM_ENABLE) || defined(__DOXYGEN__) +# warning CONF_PAGE_CHECKSUM_ENABLE is not defined, assuming false. + +/** Configuration option, page checksum enabled. + */ +# define CONF_PAGE_CHECKSUM_ENABLE false +#endif + +/** + * \internal + * Magic key is the sequence "AtEEPROMEmu_RWW." in ASCII. The key is encoded as a + * sequence of 32-bit values to speed up checking of the key, which can be + * implemented as a number of simple integer comparisons, + */ +#define RWW_EEPROM_MAGIC_KEY {0x41744545, 0x50524f4d, 0x456d752d,0x5257572e} + +/** \internal + * Length of the magic key, in 32-bit elements. + */ +#define RWW_EEPROM_MAGIC_KEY_COUNT 4 + +/** \internal + * RWW EEPROM max logical page num. + */ +#define RWW_EEPROM_MAX_LOGICAL_PAGES (((NVMCTRL_RWWEE_PAGES - (2 * NVMCTRL_ROW_PAGES)) \ + / NVMCTRL_ROW_PAGES) * CONF_LOGICAL_PAGE_NUM_IN_ROW) + +COMPILER_PACK_SET(1); +/** + * \internal + * \brief Structure describing the EEPROM Emulation master page. + */ +struct _rww_eeprom_master_page { + /** Magic key which in ASCII will show as AtEEPROMEmu_RWW. */ + uint32_t magic_key[RWW_EEPROM_MAGIC_KEY_COUNT]; + + /** Emulator major version information. */ + uint8_t major_version; + /** Emulator minor version information. */ + uint8_t minor_version; + /** Emulator revision version information. */ + uint8_t revision; + + /** Emulator identification value (to distinguish between different emulator + * schemes that carry the same version numbers). */ + uint8_t emulator_id; + + /** Unused reserved bytes in the master page. */ + uint8_t reserved[44]; +}; + +/** + * \internal + * \brief Structure describing emulated pages of RWW EEPROM data. + */ +struct _rww_eeprom_page { + /** Header information of the RWW EEPROM page. */ + struct { + uint8_t logical_page; + uint8_t page_checksum; + uint8_t reserved[RWW_EEPROM_HEADER_SIZE - 2]; + } header; + + /** Data content of the RWW EEPROM page. */ + uint8_t data[RWW_EEPROM_PAGE_SIZE]; +}; +COMPILER_PACK_RESET(); + +/** + * \internal + * \brief Internal device instance struct. + */ +struct _rww_eeprom_module { + /** Initialization state of the RWW EEPROM emulator. */ + bool initialized; + + /** Absolute byte pointer to the first byte of memory where the emulated + * RWW EEPROM is stored. */ + const struct _rww_eeprom_page *rwwee_addr; + + /** Number of physical pages occupied by the RWW EEPROM emulator. */ + uint16_t physical_pages; + /** Number of logical pages occupied by the RWW EEPROM emulator. */ + uint8_t logical_pages; + + /** Mapping array from logical RWW EEPROM pages to physical pages. */ + uint8_t page_map[RWW_EEPROM_MAX_LOGICAL_PAGES]; + + /** Row number for the spare row (used by next write). */ + uint8_t spare_row; + + /** Buffer to hold the currently cached page. */ + struct _rww_eeprom_page cache; + /** Indicates if the cache contains valid data. */ + bool cache_active; +}; + +/** + * \internal + * \brief Internal RWW EEPROM emulator instance. + */ +static struct _rww_eeprom_module _eeprom_instance = { + .initialized = false, +}; + +/** \internal + * \brief RWW EEPROM Page Checksum. + * + * \param[in] buffer Pointer of page data + * + * \return Checksum result. + */ +static uint8_t _rww_eeprom_emulator_page_checksum( + const uint8_t * buffer) +{ + uint16_t sum=0; + for(uint8_t i = 0; i < RWW_EEPROM_PAGE_SIZE;i++){ + sum += buffer[i]; + } + return (uint8_t)(sum & 0xff); +} + +/** \internal + * \brief Erases a given row within the physical RWW EEPROM memory space. + * + * \param[in] row Physical row in RWW EEPROM space to erase + */ +static void _rww_eeprom_emulator_nvm_erase_row( + const uint8_t row) +{ + enum status_code error_code = STATUS_OK; + + do { + error_code = nvm_erase_row( + (uint32_t)&_eeprom_instance.rwwee_addr[row * NVMCTRL_ROW_PAGES]); + } while (error_code == STATUS_BUSY); +} + +/** \internal + * \brief Fills the internal NVM controller page buffer in physical RWW EEPROM memory space. + * + * \param[in] physical_page Physical page in RWW EEPROM space to fill + * \param[in] data Data to write to the physical memory page + */ +static void _rww_eeprom_emulator_nvm_fill_cache( + const uint16_t physical_page, + const void* const data) +{ + enum status_code error_code = STATUS_OK; + + if (CONF_PAGE_CHECKSUM_ENABLE && (_eeprom_instance.initialized)){ + struct _rww_eeprom_page *temp = (struct _rww_eeprom_page *)data; + temp->header.page_checksum = _rww_eeprom_emulator_page_checksum(temp->data); + } + + do { + error_code = nvm_write_buffer( + (uint32_t)&_eeprom_instance.rwwee_addr[physical_page], + (uint8_t*)data, + NVMCTRL_PAGE_SIZE); + } while (error_code == STATUS_BUSY); +} + +/** \internal + * \brief Commits the internal NVM controller page buffer to physical memory. + * + * \param[in] physical_page Physical page in RWW EEPROM space to commit + */ +static void _rww_eeprom_emulator_nvm_commit_cache( + const uint16_t physical_page) +{ + enum status_code error_code = STATUS_OK; + + do { + error_code = nvm_execute_command( + NVM_COMMAND_RWWEE_WRITE_PAGE, + (uint32_t)&_eeprom_instance.rwwee_addr[physical_page], 0); + } while (error_code == STATUS_BUSY); +} + +/** \internal + * \brief Reads a page of data stored in physical RWW EEPROM memory space. + * + * \param[in] physical_page Physical page in RWW EEPROM space to read + * \param[out] data Destination buffer to fill with the read data + * + * \return Whether the page data checksum is correct. + * + * \retval \c true The page data checksum is correct + * \retval \c false The page data checksum is wrong + */ +static bool _rww_eeprom_emulator_nvm_read_page( + const uint16_t physical_page, + void* const data) +{ + enum status_code error_code = STATUS_OK; + + do { + error_code = nvm_read_buffer( + (uint32_t)&_eeprom_instance.rwwee_addr[physical_page], + (uint8_t*)data, + NVMCTRL_PAGE_SIZE); + } while (error_code == STATUS_BUSY); + + if (CONF_PAGE_CHECKSUM_ENABLE && (_eeprom_instance.initialized)){ + struct _rww_eeprom_page *temp= (struct _rww_eeprom_page *) data; + if (temp->header.page_checksum == + _rww_eeprom_emulator_page_checksum(temp->data)){ + return true; + } else { + return false; + } + } + return true; +} + +/** + * \brief Initializes the emulated RWW EEPROM memory, destroying the current contents. + */ +static void _rww_eeprom_emulator_format_memory(void) +{ + uint16_t logical_page = 0; + + /* Set row 0 as the spare row */ + _eeprom_instance.spare_row = 0; + _rww_eeprom_emulator_nvm_erase_row(_eeprom_instance.spare_row); + + for (uint16_t physical_page = NVMCTRL_ROW_PAGES; + physical_page < _eeprom_instance.physical_pages; physical_page++) { + + if (physical_page == RWW_EEPROM_MASTER_PAGE_NUMBER) { + continue; + } + + /* If we are at the first page in a new row, erase the entire row */ + if ((physical_page % NVMCTRL_ROW_PAGES) == 0) { + _rww_eeprom_emulator_nvm_erase_row(physical_page / NVMCTRL_ROW_PAGES); + } + + /* One or two logical pages are stored in each physical row; program in a + * pair of initialized but blank set of emulated RWW EEPROM pages */ + if ((physical_page % NVMCTRL_ROW_PAGES) < CONF_LOGICAL_PAGE_NUM_IN_ROW) { + /* Make a buffer to hold the initialized EEPROM page */ + struct _rww_eeprom_page data; + memset(&data, 0xFF, sizeof(data)); + + /* Set up the new EEPROM row's header */ + data.header.logical_page = logical_page; + + /* Write the page out to physical memory */ + _rww_eeprom_emulator_nvm_fill_cache(physical_page, &data); + _rww_eeprom_emulator_nvm_commit_cache(physical_page); + + /* Increment the logical RWW EEPROM page address now that the current + * address' page has been initialized */ + logical_page++; + } + } +} + +/** + * \brief Check if a row is a full row + * because the page is a invalid page, so if two pages have data, + * it is the full row. + * + * \param[in] phy_page Physical page that in a row + */ +static bool _rww_eeprom_emulator_is_full_row(uint16_t phy_page) +{ + if (CONF_LOGICAL_PAGE_NUM_IN_ROW == RWWEE_LOGICAL_PAGE_NUM_1) { + if(_eeprom_instance.rwwee_addr[phy_page].header.logical_page + == _eeprom_instance.rwwee_addr[phy_page+1].header.logical_page) { + return true; + } else { + return false; + } + } else { + if((_eeprom_instance.rwwee_addr[phy_page].header.logical_page + == _eeprom_instance.rwwee_addr[phy_page+2].header.logical_page) + || (_eeprom_instance.rwwee_addr[phy_page+1].header.logical_page + == _eeprom_instance.rwwee_addr[phy_page+2].header.logical_page )) { + return true; + } else { + return false; + } + } +} + +/** + * \brief Erase one invalid page according to two invalid physical page + * + * \param[in] pre_phy_page One physical invalid page + * \param[in] next_phy_page Another physical invalid page + */ +static void _rww_eeprom_emulator_erase_invalid_page(uint16_t pre_phy_page,uint16_t next_phy_page) +{ + bool flag; + struct _rww_eeprom_page temp; + flag = _rww_eeprom_emulator_is_full_row(pre_phy_page); + if(CONF_PAGE_CHECKSUM_ENABLE) { + if(flag) { + /* If the new row checksum is ok, erase the old one*/ + if(_rww_eeprom_emulator_nvm_read_page(next_phy_page,&temp)) { + _rww_eeprom_emulator_nvm_erase_row(pre_phy_page/4); + } else { + _rww_eeprom_emulator_nvm_erase_row(next_phy_page/4); + } + } else { + if(_rww_eeprom_emulator_nvm_read_page(pre_phy_page,&temp)) { + _rww_eeprom_emulator_nvm_erase_row(next_phy_page/4); + } else { + _rww_eeprom_emulator_nvm_erase_row(pre_phy_page/4); + } + } + } else { + /* Erase the old/full row*/ + if(flag) { + _rww_eeprom_emulator_nvm_erase_row(pre_phy_page/4); + } else { + _rww_eeprom_emulator_nvm_erase_row(next_phy_page/4); + } + } +} + +/** + * \brief Check if there exist rows with same logical pages due to power drop + * when writing or erasing page. + * when existed same logical page, if the new row checksums is valid, + * the old(full) row will be erased, or the new row will be erased. + * If page checksum disabled, the old(full) row will be erased. + */ +static void _rww_eeprom_emulator_check_logical_page(void) +{ + uint16_t i = 0, j = 0; + for (i = 0; i < _eeprom_instance.physical_pages; i=i+4) { + + uint16_t pre_logical_page = _eeprom_instance.rwwee_addr[i].header.logical_page; + if( pre_logical_page == RWW_EEPROM_INVALID_PAGE_NUMBER) { + continue; + } + + for (j = NVMCTRL_ROW_PAGES+i; j < _eeprom_instance.physical_pages; j=j+4) { + + if (j == RWW_EEPROM_MASTER_PAGE_NUMBER) { + continue; + } + uint16_t next_logical_page = _eeprom_instance.rwwee_addr[j].header.logical_page; + if( next_logical_page == RWW_EEPROM_INVALID_PAGE_NUMBER) { + continue; + } + + if(pre_logical_page == next_logical_page) { + /* Found invalid logical page and erase it */ + _rww_eeprom_emulator_erase_invalid_page(i,j); + } + } + } +} + +/** + * \brief Creates a map in SRAM to translate logical RWW EEPROM pages to physical pages. + */ +static void _rww_eeprom_emulator_update_page_mapping(void) +{ + /* Check if exists invalid logical page */ + _rww_eeprom_emulator_check_logical_page(); + + /* Scan through all physical pages, to map physical and logical pages */ + for (uint16_t c = 0; c < _eeprom_instance.physical_pages; c++) { + if (c == RWW_EEPROM_MASTER_PAGE_NUMBER) { + continue; + } + + /* Read in the logical page stored in the current physical page */ + uint16_t logical_page = _eeprom_instance.rwwee_addr[c].header.logical_page; + + /* If the logical page number is valid, add it to the mapping */ + if ((logical_page != RWW_EEPROM_INVALID_PAGE_NUMBER) && + (logical_page < _eeprom_instance.logical_pages)) { + _eeprom_instance.page_map[logical_page] = c; + } + } + + /* Use an invalid page number as the spare row until a valid one has been + * found */ + _eeprom_instance.spare_row = RWW_EEPROM_INVALID_ROW_NUMBER; + + /* Scan through all physical rows, to find an erased row to use as the + * spare */ + for (uint16_t c = 0; c < (_eeprom_instance.physical_pages / NVMCTRL_ROW_PAGES); c++) { + bool spare_row_found = true; + + /* Look through pages within the row to see if they are all erased */ + for (uint8_t c2 = 0; c2 < NVMCTRL_ROW_PAGES; c2++) { + uint16_t physical_page = (c * NVMCTRL_ROW_PAGES) + c2; + + if (physical_page == RWW_EEPROM_MASTER_PAGE_NUMBER) { + continue; + } + + if (_eeprom_instance.rwwee_addr[physical_page].header.logical_page != + RWW_EEPROM_INVALID_PAGE_NUMBER) { + spare_row_found = false; + } + } + + /* If we've now found the spare row, store it and abort the search */ + if (spare_row_found == true) { + _eeprom_instance.spare_row = c; + break; + } + } +} + +/** + * \brief Finds the next free page in the given row if one is available. + * + * \param[in] start_physical_page Physical page index of the row to + * search + * \param[out] free_physical_page Index of the physical page that is + * currently free (if one was found) + * + * \return Whether a free page was found in the specified row. + * + * \retval \c true If a free page was found + * \retval \c false If the specified row was full and needs an erase + */ +static bool _rww_eeprom_emulator_is_page_free_on_row( + const uint8_t start_physical_page, + uint8_t *const free_physical_page) +{ + /* Convert physical page number to a RWWEE row and page within the row */ + uint8_t row = (start_physical_page / NVMCTRL_ROW_PAGES); + uint8_t page_in_row = (start_physical_page % NVMCTRL_ROW_PAGES); + + /* Look in the current row for a page that isn't currently used */ + for (uint8_t c = page_in_row; c < NVMCTRL_ROW_PAGES; c++) { + /* Calculate the page number for the current page being examined */ + uint8_t page = (row * NVMCTRL_ROW_PAGES) + c; + + /* If the page is free, pass it to the caller and exit */ + if (_eeprom_instance.rwwee_addr[page].header.logical_page == + RWW_EEPROM_INVALID_PAGE_NUMBER) { + *free_physical_page = page; + return true; + } + } + + /* No free page in the current row was found */ + return false; +} + +/** + * \brief Moves data from the specified logical page to the spare row. + * + * Moves the contents of the specified row into the spare row, so that the + * original row can be erased and re-used. The contents of the given logical + * page is replaced with a new buffer of data. + * + * \param[in] row_number Physical row to examine + * \param[in] logical_page Logical RWW EEPROM page number in the row to update + * \param[in] data New data to replace the old in the logical page + * + * \return Status code indicating the status of the operation. + */ +static enum status_code _rww_eeprom_emulator_move_data_to_spare( + const uint8_t row_number, + const uint8_t logical_page, + const uint8_t *const data) +{ + enum status_code error_code = STATUS_OK; + struct { + uint8_t logical_page; + uint8_t physical_page; + } page_trans[CONF_LOGICAL_PAGE_NUM_IN_ROW]; + + const struct _rww_eeprom_page *row_data = + (struct _rww_eeprom_page *)&_eeprom_instance.rwwee_addr[row_number * NVMCTRL_ROW_PAGES]; + + /* There should be one or two logical pages of data in each row, possibly with + * multiple revisions (right-most version is the newest). Start by assuming + * the left-most two pages contain the newest page revisions. */ + for (uint8_t i = 0; i < CONF_LOGICAL_PAGE_NUM_IN_ROW; i++){ + page_trans[i].logical_page = row_data[i].header.logical_page; + page_trans[i].physical_page = (row_number * NVMCTRL_ROW_PAGES) + i; + } + + /* Look for newer revisions of the one or two logical pages stored in the row */ + for (uint8_t c = 0; c < CONF_LOGICAL_PAGE_NUM_IN_ROW; c++) { + /* Look through the remaining pages in the row for any newer revisions */ + for (uint8_t c2 = CONF_LOGICAL_PAGE_NUM_IN_ROW; c2 < NVMCTRL_ROW_PAGES; c2++) { + if (page_trans[c].logical_page == row_data[c2].header.logical_page) { + page_trans[c].physical_page = + (row_number * NVMCTRL_ROW_PAGES) + c2; + } + } + } + + /* Need to move saved logical pages stored in the same row */ + for (uint8_t c = 0; c < CONF_LOGICAL_PAGE_NUM_IN_ROW; c++) { + /* Find the physical page index for the new spare row pages */ + uint32_t new_page = + ((_eeprom_instance.spare_row * NVMCTRL_ROW_PAGES) + c); + + /* Commit any cached data to physical non-volatile memory */ + rww_eeprom_emulator_commit_page_buffer(); + + /* Check if we we are looking at the page the calling function wishes + * to change during the move operation */ + if (logical_page == page_trans[c].logical_page) { + /* Fill out new (updated) logical page's header in the cache */ + _eeprom_instance.cache.header.logical_page = logical_page; + + /* Write data to SRAM cache */ + memcpy(_eeprom_instance.cache.data, data, RWW_EEPROM_PAGE_SIZE); + } else { + /* Copy existing RWW EEPROM page to cache buffer wholesale */ + _rww_eeprom_emulator_nvm_read_page( + page_trans[c].physical_page, &_eeprom_instance.cache); + } + + /* Fill the physical NVM buffer with the new data so that it can be + * quickly committed in the future if needed due to a low power + * condition */ + _rww_eeprom_emulator_nvm_fill_cache(new_page, &_eeprom_instance.cache); + + /* Update the page map with the new page location and indicate that + * the cache now holds new data */ + _eeprom_instance.page_map[page_trans[c].logical_page] = new_page; + _eeprom_instance.cache_active = true; + } +#ifdef SAMD21_64K + rww_eeprom_emulator_commit_page_buffer(); +#endif + /* Erase the row that was moved and set it as the new spare row */ + _rww_eeprom_emulator_nvm_erase_row(row_number); + + /* Keep the index of the new spare row */ + _eeprom_instance.spare_row = row_number; + + return error_code; +} + +/** + * \brief Create master emulated RWW EEPROM management page. + * + * Creates a new master page in emulated RWW EEPROM, giving information on the + * emulator used to store the RWW EEPROM data. + */ +static void _rww_eeprom_emulator_create_master_page(void) +{ + const uint32_t magic_key[] = RWW_EEPROM_MAGIC_KEY; + + struct _rww_eeprom_master_page master_page; + memset(&master_page, 0xFF, sizeof(master_page)); + + /* Fill out the magic key header to indicate an initialized master page */ + for (uint8_t c = 0; c < RWW_EEPROM_MAGIC_KEY_COUNT; c++) { + master_page.magic_key[c] = magic_key[c]; + } + + /* Update master header with version information of this emulator */ + master_page.emulator_id = RWW_EEPROM_EMULATOR_ID; + master_page.major_version = RWW_EEPROM_MAJOR_VERSION; + master_page.minor_version = RWW_EEPROM_MINOR_VERSION; + master_page.revision = RWW_EEPROM_REVISION; + + _rww_eeprom_emulator_nvm_erase_row( + RWW_EEPROM_MASTER_PAGE_NUMBER / NVMCTRL_ROW_PAGES); + + /* Write the new master page data to physical memory */ + _rww_eeprom_emulator_nvm_fill_cache(RWW_EEPROM_MASTER_PAGE_NUMBER, &master_page); + _rww_eeprom_emulator_nvm_commit_cache(RWW_EEPROM_MASTER_PAGE_NUMBER); +} + +/** + * \brief Verify the contents of a master RWW EEPROM page. + * + * Verify the contents of a master RWW EEPROM page to ensure that it contains the + * correct information for this version of the RWW EEPROM emulation service. + * + * \retval STATUS_OK Given master page contents is valid + * \retval STATUS_ERR_BAD_FORMAT Master page contents was invalid + * \retval STATUS_ERR_IO Master page indicates the data is incompatible + * with this version of the RWW EEPROM emulator + */ +static enum status_code _rww_eeprom_emulator_verify_master_page(void) +{ + const uint32_t magic_key[] = RWW_EEPROM_MAGIC_KEY; + struct _rww_eeprom_master_page master_page; + + /* Copy the master page to the RAM buffer so that it can be inspected */ + _rww_eeprom_emulator_nvm_read_page(RWW_EEPROM_MASTER_PAGE_NUMBER, &master_page); + + /* Verify magic key is correct in the master page header */ + for (uint8_t c = 0; c < RWW_EEPROM_MAGIC_KEY_COUNT; c++) { + if (master_page.magic_key[c] != magic_key[c]) { + return STATUS_ERR_BAD_FORMAT; + } + } + + /* Verify emulator ID in header to ensure the same scheme is used */ + if (master_page.emulator_id != RWW_EEPROM_EMULATOR_ID) { + return STATUS_ERR_IO; + } + + /* Verify major version in header to ensure the same version is used */ + if (master_page.major_version != RWW_EEPROM_MAJOR_VERSION) { + return STATUS_ERR_IO; + } + + /* Verify minor version in header to ensure the same version is used */ + if (master_page.minor_version != RWW_EEPROM_MINOR_VERSION) { + return STATUS_ERR_IO; + } + + /* Don't verify revision number - same major/minor is considered enough + * to ensure the stored data is compatible. */ + + return STATUS_OK; +} + + +/** + * \brief Retrieves the parameters of the RWW EEPROM Emulator memory layout. + * + * Retrieves the configuration parameters of the RWW EEPROM Emulator, after it has + * been initialized. + * + * \param[out] parameters RWW EEPROM Emulator parameter struct to fill + * + * \return Status of the operation. + * + * \retval STATUS_OK If the emulator parameters were retrieved + * successfully + * \retval STATUS_ERR_NOT_INITIALIZED If the RWW EEPROM Emulator is not initialized + */ +enum status_code rww_eeprom_emulator_get_parameters( + struct rww_eeprom_emulator_parameters *const parameters) +{ + if (_eeprom_instance.initialized == false) { + return STATUS_ERR_NOT_INITIALIZED; + } + + parameters->page_size = RWW_EEPROM_PAGE_SIZE; + parameters->eeprom_number_of_pages = _eeprom_instance.logical_pages; + + return STATUS_OK; +} + +/** + * \brief Initializes the RWW EEPROM Emulator service. + * + * Initializes the emulated RWW EEPROM memory space. If the emulated RWW EEPROM memory + * has not been previously initialized, it will need to be explicitly formatted + * via \ref rww_eeprom_emulator_erase_memory(). The RWW EEPROM memory space will \b not + * be automatically erased by the initialization function. Partial data + * may be recovered by the user application manually if the service is unable to + * initialize successfully. + * + * \return Status code indicating the status of the operation. + * + * \retval STATUS_OK RWW EEPROM emulation service was successfully + * initialized + * \retval STATUS_ERR_BAD_FORMAT Emulated RWW EEPROM memory is corrupt or not + * formatted + * \retval STATUS_ERR_IO RWW EEPROM data is incompatible with this version + * or scheme of the RWW EEPROM emulator + * \retval STATUS_ERR_INVALID_ARG Invalid logical page configuration + */ +enum status_code rww_eeprom_emulator_init(void) +{ + enum status_code error_code = STATUS_OK; + struct nvm_config config; + struct nvm_parameters parameters; + + /* Mark initialization as start */ + _eeprom_instance.initialized = false; + + if (!(CONF_LOGICAL_PAGE_NUM_IN_ROW == RWWEE_LOGICAL_PAGE_NUM_1 || + CONF_LOGICAL_PAGE_NUM_IN_ROW == RWWEE_LOGICAL_PAGE_NUM_2)){ + return STATUS_ERR_INVALID_ARG; + } + /* Retrieve the NVM controller configuration - enable manual page writing + * mode so that the emulator has exclusive control over page writes to + * allow for caching */ + nvm_get_config_defaults(&config); + config.manual_page_write = true; + + /* Apply new NVM configuration */ + do { + error_code = nvm_set_config(&config); + } while (error_code == STATUS_BUSY); + + /* Get the NVM controller configuration parameters */ + nvm_get_parameters(¶meters); + + /* Configure the RWW EEPROM instance physical and logical number of pages: + * - One row is reserved for the master page + * - One row is reserved for the spare row + * - One or two logical pages can be stored in one physical row + */ + _eeprom_instance.physical_pages = + parameters.rww_eeprom_number_of_pages; + _eeprom_instance.logical_pages = RWW_EEPROM_MAX_LOGICAL_PAGES; + + /* Configure the RWW EEPROM instance starting physical address and + * pre-compute the index of the first page used for RWW EEPROM */ + _eeprom_instance.rwwee_addr = (void*)NVMCTRL_RWW_EEPROM_ADDR; + + /* Clear RWW EEPROM page write cache on initialization */ + _eeprom_instance.cache_active = false; + + /* Scan physical memory and re-create logical to physical page mapping + * table to locate logical pages of RWW EEPROM data */ + _rww_eeprom_emulator_update_page_mapping(); + + /* Could not find spare row - abort as the memory appears to be corrupt */ + if (_eeprom_instance.spare_row == RWW_EEPROM_INVALID_ROW_NUMBER) { + return STATUS_ERR_BAD_FORMAT; + } + + /* Verify that the master page contains valid data for this service */ + error_code = _rww_eeprom_emulator_verify_master_page(); + if (error_code != STATUS_OK) { + return error_code; + } + + /* Mark initialization as complete */ + _eeprom_instance.initialized = true; + + return error_code; +} + +/** + * \brief Erases the entire emulated RWW EEPROM memory space. + * + * Erases and re-initializes the emulated RWW EEPROM memory space, destroying any + * existing data. + */ +void rww_eeprom_emulator_erase_memory(void) +{ + /* Create new RWW EEPROM memory block in EEPROM emulation section */ + _rww_eeprom_emulator_format_memory(); + + bool temp = _eeprom_instance.initialized; + + /** Master page should be created during uninitialized status*/ + _eeprom_instance.initialized = false; + + /* Write RWW EEPROM emulation master block */ + _rww_eeprom_emulator_create_master_page(); + _eeprom_instance.initialized = temp; + + /* Map the newly created RWW EEPROM memory block */ + _rww_eeprom_emulator_update_page_mapping(); +} + +/** + * \brief Writes a page of data to an emulated RWW EEPROM memory page. + * + * Writes an emulated RWW EEPROM page of data to the emulated RWW EEPROM memory space. + * + * \note Data stored in pages may be cached in volatile RAM memory; to commit + * any cached data to physical non-volatile memory, the + * \ref rww_eeprom_emulator_commit_page_buffer() function should be called. + * + * \param[in] logical_page Logical RWW EEPROM page number to write to + * \param[in] data Pointer to the data buffer containing source data to + * write + * + * \return Status code indicating the status of the operation. + * + * \retval STATUS_OK If the page was successfully read + * \retval STATUS_ERR_NOT_INITIALIZED If the RWW EEPROM emulator is not initialized + * \retval STATUS_ERR_BAD_ADDRESS If an address outside the valid emulated + * RWW EEPROM memory space was supplied + */ +enum status_code rww_eeprom_emulator_write_page( + const uint8_t logical_page, + const uint8_t *const data) +{ + /* Ensure the emulated RWW EEPROM has been initialized first */ + if (_eeprom_instance.initialized == false) { + return STATUS_ERR_NOT_INITIALIZED; + } + + /* Make sure the write address is within the allowable address space */ + if (logical_page >= _eeprom_instance.logical_pages) { + return STATUS_ERR_BAD_ADDRESS; + } + + /* Check if the cache is active and the currently cached page is not the + * page that is being written (if not, we need to commit and cache the new + * page) */ + if ((_eeprom_instance.cache_active == true) && + (_eeprom_instance.cache.header.logical_page != logical_page)) { + /* Commit the currently cached data buffer to non-volatile memory */ + rww_eeprom_emulator_commit_page_buffer(); + } + + /* Check if we have space in the current page location's physical row for + * a new version, and if so get the new page index */ + uint8_t new_page = 0; + bool page_spare = _rww_eeprom_emulator_is_page_free_on_row( + _eeprom_instance.page_map[logical_page], &new_page); + + /* Check if the current row is full, and we need to swap it out with a + * spare row */ + if (page_spare == false) { + /* Move the other page we aren't writing that is stored in the same + * page to the new row, and replace the old current page with the + * new page contents (cache is updated to match) */ + _rww_eeprom_emulator_move_data_to_spare( + _eeprom_instance.page_map[logical_page] / NVMCTRL_ROW_PAGES, + logical_page, + data); + + /* New data is now written and the cache is updated, exit */ + return STATUS_OK; + } + + /* Update the page cache header section with the new page header */ + _eeprom_instance.cache.header.logical_page = logical_page; + + /* Update the page cache contents with the new data */ + memcpy(&_eeprom_instance.cache.data, + data, + RWW_EEPROM_PAGE_SIZE); + + /* Fill the physical NVM buffer with the new data so that it can be quickly + * committed in the future if needed due to a low power condition */ + _rww_eeprom_emulator_nvm_fill_cache(new_page, &_eeprom_instance.cache); + + /* Update the cache parameters and mark the cache as active */ + _eeprom_instance.page_map[logical_page] = new_page; + barrier(); // Enforce ordering to prevent incorrect cache state + _eeprom_instance.cache_active = true; + + return STATUS_OK; +} + +/** + * \brief Reads a page of data from an emulated RWW EEPROM memory page. + * + * Reads an emulated RWW EEPROM page of data from the emulated RWW EEPROM memory space. + * + * \param[in] logical_page Logical RWW EEPROM page number to read from + * \param[out] data Pointer to the destination data buffer to fill + * + * \return Status code indicating the status of the operation. + * + * \retval STATUS_OK If the page was successfully read + * \retval STATUS_ERR_NOT_INITIALIZED If the RWW EEPROM emulator is not initialized + * \retval STATUS_ERR_BAD_ADDRESS If an address outside the valid emulated + * RWW EEPROM memory space was supplied + * \retval STATUS_ERR_BAD_FORMAT Page data checksum is not correct, maybe data + * is damaged + */ +enum status_code rww_eeprom_emulator_read_page( + const uint8_t logical_page, + uint8_t *const data) +{ + /* Ensure the emulated RWW EEPROM has been initialized first */ + if (_eeprom_instance.initialized == false) { + return STATUS_ERR_NOT_INITIALIZED; + } + + /* Make sure the read address is within the allowable address space */ + if (logical_page >= _eeprom_instance.logical_pages) { + return STATUS_ERR_BAD_ADDRESS; + } + + /* Check if the page to read is currently cached (and potentially out of + * sync/newer than the physical memory) */ + if ((_eeprom_instance.cache_active == true) && + (_eeprom_instance.cache.header.logical_page == logical_page)) { + /* Copy the potentially newer cached data into the user buffer */ + memcpy(data, _eeprom_instance.cache.data, RWW_EEPROM_PAGE_SIZE); + } else { + struct _rww_eeprom_page temp; + + /* Copy the data from non-volatile memory into the temporary buffer */ + if (_rww_eeprom_emulator_nvm_read_page( + _eeprom_instance.page_map[logical_page], &temp)){ + /* Copy the data portion of the read page to the user's buffer */ + memcpy(data, temp.data, RWW_EEPROM_PAGE_SIZE); + }else{ + /* Copy data even the checksum is not correct */ + memcpy(data, temp.data, RWW_EEPROM_PAGE_SIZE); + return STATUS_ERR_BAD_FORMAT; + } + } + + return STATUS_OK; +} + +/** + * \brief Writes a buffer of data to the emulated RWW EEPROM memory space. + * + * Writes a buffer of data to a section of emulated RWW EEPROM memory space. The + * source buffer may be of any size, and the destination may lie outside of an + * emulated RWW EEPROM page boundary. + * + * \note Data stored in pages may be cached in volatile RAM memory; to commit + * any cached data to physical non-volatile memory, the + * \ref rww_eeprom_emulator_commit_page_buffer() function should be called. + * + * \param[in] offset Starting byte offset to write to, in emulated RWW EEPROM + * memory space + * \param[in] data Pointer to the data buffer containing source data to write + * \param[in] length Length of the data to write, in bytes + * + * \return Status code indicating the status of the operation. + * + * \retval STATUS_OK If the page was successfully read + * \retval STATUS_ERR_NOT_INITIALIZED If the RWW EEPROM emulator is not initialized + * \retval STATUS_ERR_BAD_ADDRESS If an address outside the valid emulated + * RWW EEPROM memory space was supplied + */ +enum status_code rww_eeprom_emulator_write_buffer( + const uint16_t offset, + const uint8_t *const data, + const uint16_t length) +{ + enum status_code error_code = STATUS_OK; + uint8_t buffer[RWW_EEPROM_PAGE_SIZE]; + uint8_t logical_page = offset / RWW_EEPROM_PAGE_SIZE; + uint16_t c = offset; + /* Keep track of whether the currently updated page has been written */ + bool page_dirty = false; + /** Perform the initial page read if necessary*/ + if ((offset % RWW_EEPROM_PAGE_SIZE) || length < RWW_EEPROM_PAGE_SIZE) { + error_code = rww_eeprom_emulator_read_page(logical_page, buffer); + + if (error_code != STATUS_OK) { + return error_code; + } + } + + /* To avoid entering into the initial if in the loop the first time */ + if ((offset % RWW_EEPROM_PAGE_SIZE) == 0) { + buffer[c % RWW_EEPROM_PAGE_SIZE] = data[c - offset]; + page_dirty = true; + c=c+1; + } + + /* Write the specified data to the emulated RWW EEPROM memory space */ + for (; c < (length + offset); c++) { + /* Check if we have written up to a new RWW EEPROM page boundary */ + if ((c % RWW_EEPROM_PAGE_SIZE) == 0) { + /* Write the current page to non-volatile memory from the temporary + * buffer */ + error_code = rww_eeprom_emulator_write_page(logical_page, buffer); + page_dirty = false; + + if (error_code != STATUS_OK) { + break; + } + + /* Increment the page number we are looking at */ + logical_page++; + + /* Read the next page from non-volatile memory into the temporary + * buffer in case of a partial page write */ + error_code = rww_eeprom_emulator_read_page(logical_page, buffer); + + if (error_code != STATUS_OK) { + return error_code; + } + } + /* Copy the next byte of data from the user's buffer to the temporary + * buffer */ + buffer[c % RWW_EEPROM_PAGE_SIZE] = data[c - offset]; + page_dirty = true; + } + + /* If the current page is dirty, write it */ + if (page_dirty) { + error_code = rww_eeprom_emulator_write_page(logical_page, buffer); + } + + return error_code; +} + +/** + * \brief Reads a buffer of data from the emulated RWW EEPROM memory space. + * + * Reads a buffer of data from a section of emulated RWW EEPROM memory space. The + * destination buffer may be of any size, and the source may lie outside of an + * emulated RWW EEPROM page boundary. + * + * \param[in] offset Starting byte offset to read from, in emulated RWW EEPROM + * memory space + * \param[out] data Pointer to the data buffer containing source data to read + * \param[in] length Length of the data to read, in bytes + * + * \return Status code indicating the status of the operation. + * + * \retval STATUS_OK If the page was successfully read + * \retval STATUS_ERR_NOT_INITIALIZED If the RWW EEPROM emulator is not initialized + * \retval STATUS_ERR_BAD_ADDRESS If an address outside the valid emulated + * RWW EEPROM memory space was supplied + */ +enum status_code rww_eeprom_emulator_read_buffer( + const uint16_t offset, + uint8_t *const data, + const uint16_t length) +{ + enum status_code error_code; + uint8_t buffer[RWW_EEPROM_PAGE_SIZE]; + uint8_t logical_page = offset / RWW_EEPROM_PAGE_SIZE; + uint16_t c = offset; + + /** Perform the initial page read */ + error_code = rww_eeprom_emulator_read_page(logical_page, buffer); + if (error_code != STATUS_OK) { + return error_code; + } + + /* To avoid entering into the initial if in the loop the first time */ + if ((offset % RWW_EEPROM_PAGE_SIZE) == 0) { + data[0] = buffer[0]; + c=c+1; + } + + /* Read in the specified data from the emulated RWW EEPROM memory space */ + for (; c < (length + offset); c++) { + /* Check if we have read up to a new RWW EEPROM page boundary */ + if ((c % RWW_EEPROM_PAGE_SIZE) == 0) { + /* Increment the page number we are looking at */ + logical_page++; + + /* Read the next page from non-volatile memory into the temporary + * buffer */ + error_code = rww_eeprom_emulator_read_page(logical_page, buffer); + + if (error_code != STATUS_OK) { + return error_code; + } + } + + /* Copy the next byte of data from the temporary buffer to the user's + * buffer */ + data[c - offset] = buffer[c % RWW_EEPROM_PAGE_SIZE]; + } + + return error_code; +} + +/** + * \brief Commits any cached data to physical non-volatile memory. + * + * Commits the internal SRAM caches to physical non-volatile memory, to ensure + * that any outstanding cached data is preserved. This function should be called + * prior to a system reset or shutdown to prevent data loss. + * + * \note This should be the first function executed in a BOD33 Early Warning + * callback to ensure that any outstanding cache data is fully written to + * prevent data loss. + * + * + * \note This function should also be called before using the NVM controller + * directly in the user-application for any other purposes to prevent + * data loss. + * + * \return Status code indicating the status of the operation. + */ +enum status_code rww_eeprom_emulator_commit_page_buffer(void) +{ + enum status_code error_code = STATUS_OK; + + /* If cache is inactive, no need to commit anything to physical memory */ + if (_eeprom_instance.cache_active == false) { + return STATUS_OK; + } + + uint8_t cached_logical_page = _eeprom_instance.cache.header.logical_page; + + /* Perform the page write to commit the NVM page buffer to physical memory */ + _rww_eeprom_emulator_nvm_commit_cache( + _eeprom_instance.page_map[cached_logical_page]); + + barrier(); // Enforce ordering to prevent incorrect cache state + _eeprom_instance.cache_active = false; + + return error_code; +} diff --git a/src/boards/mcu/samr34/ASF/sam0/services/eeprom/emulator/rwwee_array/rww_eeprom.h b/src/boards/mcu/samr34/ASF/sam0/services/eeprom/emulator/rwwee_array/rww_eeprom.h new file mode 100644 index 000000000..b0ca85bd3 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/services/eeprom/emulator/rwwee_array/rww_eeprom.h @@ -0,0 +1,549 @@ +/** + * \file + * + * \brief SAM Read While Write EEPROM Emulator + * + * Copyright (c) 2014-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ +#ifndef RWW_EEPROM_H_INCLUDED +#define RWW_EEPROM_H_INCLUDED + +/** + * \defgroup asfdoc_sam0_rww_eeprom_group SAM Read While Write EEPROM (RWW EEPROM) Emulator Service + * + * This driver for Atmel® | SMART ARM®-based microcontrollers provides an RWW emulated EEPROM + * memory area, for the storage and retrieval of user-application + * configuration data into and out of non-volatile memory. The main array + * can therefore run code while EEPROM data is written. + * + * The following peripheral is used by this module: + * - NVM (Non-Volatile Memory Controller) + * + * The following devices can use this module: + * - Atmel | SMART SAM L21/L22 + * - Atmel | SMART SAM D21 + * - Atmel | SMART SAM C20/C21 + * - Atmel | SMART SAM DA1 + * - Atmel | SMART SAM HA1 + * + * The outline of this documentation is as follows: + * - \ref asfdoc_sam0_rww_eeprom_prerequisites + * - \ref asfdoc_sam0_rww_eeprom_module_overview + * - \ref asfdoc_sam0_rww_eeprom_special_considerations + * - \ref asfdoc_sam0_rww_eeprom_extra_info + * - \ref asfdoc_sam0_rww_eeprom_examples + * - \ref asfdoc_sam0_rww_eeprom_api_overview + * + * + * \section asfdoc_sam0_rww_eeprom_prerequisites Prerequisites + * There are no prerequisites for this module. + * + * + * \section asfdoc_sam0_rww_eeprom_module_overview Module Overview + * + * SAM devices embeds a separate read while write EEPROM emulation (RWWEE) array + * that can be programmed while the main array is not blocked. + * To use RWWEE memory, data must be written as a number of physical memory pages + * (of several bytes each) rather than being individually byte addressable, and + * entire rows of RWWEE must be erased before new data may be stored. + * To help abstract these characteristics away from the user application an + * emulation scheme is implemented to present a more user-friendly API for + * data storage and retrieval. + * + * This module provides an RWW EEPROM emulation layer on top of the device's + * internal NVM controller, to provide a standard interface for the reading and + * writing of non-volatile configuration data. This data is placed into the + * RWW EEPROM emulated section. Emulated EEPROM is exempt from the usual device + * NVM region lock bits, so that it may be read from or written to at any point + * in the user application. + * + * There are many different algorithms that may be employed for EEPROM emulation, + * to tune the write and read latencies, RAM usage, wear + * levelling, and other characteristics. As a result, multiple different emulator + * schemes may be implemented, so that the most appropriate scheme for a + * specific application's requirements may be used. + * + * \subsection asfdoc_sam0_rww_eeprom_module_overview_implementation Implementation Details + * The following information is relevant for RWW EEPROM Emulator scheme 1, + * version 1.0.0, as implemented by this module. Other revisions or + * emulation schemes may vary in their implementation details and may have + * different wear-leveling, latency, and other characteristics. + * + * \subsubsection asfdoc_sam0_rww_eeprom_module_overview_implementation_ec Emulator Characteristics + * This emulator is designed for best reliability, with a good balance of + * available storage and write-cycle limits. It is designed to ensure that + * page data is updated by an atomic operation, so that in the event of a failed update the + * previous data is not lost (when used correctly). With the exception of a + * system reset with data cached to the internal write-cache buffer, at most + * only the latest write to physical non-volatile memory will be lost in the + * event of a failed write. + * + * This emulator scheme is tuned to give best write-cycle longevity when writes + * are confined to the same logical RWW EEPROM page (where possible) and when writes + * across multiple logical RWW EEPROM pages are made in a linear fashion through the + * entire emulated RWW EEPROM space. + * + * \subsubsection asfdoc_sam0_rww_eeprom_module_overview_implementation_pf Physical Memory + * RWW EEPROM emulator is divided into a number of physical rows, each + * containing four identically sized pages. Pages may be read or written + * to individually, however, pages must be erased before being reprogrammed and + * the smallest granularity available for erasure is one single row. + * + * This discrepancy results in the need for an emulator scheme that is able to + * handle the versioning and moving of page data to different physical rows as + * needed, erasing old rows ready for re-use by future page write operations. + * + * Physically, the emulated RWW EEPROM segment is a dedicated space that are memory + * mapped, as shown in + * \ref asfdoc_sam0_rww_eeprom_module_mem_layout "the figure below". + * + * \anchor asfdoc_sam0_rww_eeprom_module_mem_layout + * \dot + * digraph memory_layout { + * size="5,5" + * node [shape=plaintext] + * memory [label=< + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
End of RWW EEPROM Memory RWW EEPROM
Start of RWW EEPROM Memory
Reserved
End of NVM Memory Reserved EEPROM Section
Start of EEPROM Memory
End of Application Memory Application Section
Start of Application Memory
End of Bootloader Memory BOOT Section
Start of NVM Memory
+ * >] + * } + * \enddot + * + * \subsubsection asfdoc_sam0_rww_eeprom_module_overview_implementation_mp Master Row + * One physical row at the end of the emulated RWW EEPROM memory space is + * reserved for use by the emulator to store configuration data. The master row + * is not user-accessible, and is reserved solely for internal use by the + * emulator. + * + * \subsubsection asfdoc_sam0_rww_eeprom_module_overview_implementation_sr Spare Row + * As data needs to be preserved between row erasures, a single row is kept + * unused to act as destination for copied data when a write request is made to + * an already full row. When the write request is made, any logical pages of + * data in the full row that need to be preserved are written to the spare row + * along with the new (updated) logical page data, before the old row is erased + * and marked as the new spare. + * + * \subsubsection asfdoc_sam0_rww_eeprom_module_overview_implementation_rc Row Contents + * Each physical row initially stores the contents of one or two logical RWW EEPROM + * memory pages (it depends on application configuration file). This quarters or + * halves the available storage space for the emulated RWW EEPROM + * but reduces the overall number of row erases that are required, by reserving + * two or three pages within each row for updated versions of the logical page contents. + * See \ref asfdoc_sam0_rww_eeprom_page_layout "here" for a visual layout of the RWW + * EEPROM Emulator physical memory. + * + * As logical pages within a physical row are updated, the new data is filled + * into the remaining unused pages in the row. Once the entire row is full, a + * new write request will copy the logical page not being written to in the + * current row to the spare row with the new (updated) logical page data, before + * the old row is erased. + * + * When it is configured, each physical row stores the contents of one logical RWW EEPROM + * memory page. This system will allow for the same logical page to be updated up + * to four times into the physical memory before a row erasure procedure is needed. + * In the case of multiple versions of the same logical RWW EEPROM page being stored in + * the same physical row, the right-most (highest physical memory page address) + * version is considered to be the most current. + * + * \subsubsection asfdoc_sam0_rww_eeprom_module_overview_implementation_wc Write Cache + * As a typical EEPROM use case is to write to multiple sections of the same + * EEPROM page sequentially, the emulator is optimized with a single logical + * RWW EEPROM page write cache to buffer writes before they are written to the + * physical backing memory store. The cache is automatically committed when a + * new write request to a different logical RWW EEPROM memory page is requested, or + * when the user manually commits the write cache. + * + * Without the write cache, each write request to an EEPROM memory page would + * require a full page write, reducing the system performance and significantly + * reducing the lifespan of the non-volatile memory. + * + * \subsection asfdoc_sam0_rww_eeprom_special_considerations_memlayout Memory Layout + * A single logical RWW EEPROM page is physically stored as the page content and a + * header inside a single physical page, as shown in + * \ref asfdoc_sam0_rww_eeprom_page_layout "the following figure". + * + * \anchor asfdoc_sam0_rww_eeprom_page_layout + * \image html page_layout.svg "Internal Layout of an Emulated RWW EEPROM Page" + * + * \note In the following memory layout example, each physical row stores the + * contents of one logical RWW EEPROM page. Refer to + * + * "AT03265: SAM EEPROM Emulator Service (EEPROM)" + * for the example of two logical EEPROM pages in one row. + * + * Within the RWW EEPROM memory reservation section at the top of the NVM memory + * space, this emulator will produce the layout as shown in + * \ref asfdoc_sam0_rww_eeprom_init_layout "the figure below" when initialized for + * the first time. + * + * \anchor asfdoc_sam0_rww_eeprom_init_layout + * \image html init_layout.svg "Initial Physical Layout of the Emulated RWW EEPROM Memory" + * + * When an RWW EEPROM page needs to be committed to physical memory, the next free + * page in the same row will be chosen. This makes recovery simple, as the + * right-most version of a logical page in a row is considered the most current. + * With four pages to a physical NVM row, this allows for up to four updates to + * the same logical page to be made before an erase is needed. + * \ref asfdoc_sam0_rww_eeprom_page_write1 "The figure below" shows the result of + * the user writing an updated version of logical EEPROM page N-1 to + * the physical memory. + * + * \anchor asfdoc_sam0_rww_eeprom_page_write1 + * \image html nm1_page_write.svg "First Write to Logical RWW EEPROM Page N-1" + * + * A second write of the same logical RWW EEPROM page results in the layout shown + * in \ref asfdoc_sam0_rww_eeprom_page_write2 "the figure below". + * + * \anchor asfdoc_sam0_rww_eeprom_page_write2 + * \image html nm1_page_write2.svg "Second Write to Logical RWW EEPROM Page N-1" + * + * A third write of the same logical RWW EEPROM page results in the layout shown + * in \ref asfdoc_sam0_rww_eeprom_page_write3 "the figure below". + * + * \anchor asfdoc_sam0_rww_eeprom_page_write3 + * \image html nm1_page_write3.svg "Third Write to Logical RWW EEPROM Page N-1" + * + * A fourth write of the same logical page requires that the RWW EEPROM emulator + * erase the row, as it has become full. Prior to this, the content of the + * unmodified page in the same row as the page being updated will be copied into + * the spare row, along with the new version of the page being updated. The old + * (full) row is then erased, resulting in the layout shown in + * \ref asfdoc_sam0_rww_eeprom_page_write4 "the figure below". + * + * \anchor asfdoc_sam0_rww_eeprom_page_write4 + * \image html nm1_page_write4.svg "Third Write to Logical RWW EEPROM Page N-1" + * + * + * \section asfdoc_sam0_rww_eeprom_special_considerations Special Considerations + * + * \subsection asfdoc_sam0_rww_eeprom_special_considerations_nvm_config NVM Controller Configuration + * The RWW EEPROM Emulator service will initialize the NVM controller as part of its + * own initialization routine; the NVM controller will be placed in Manual Write + * mode, so that explicit write commands must be sent to the controller to + * commit a buffered page to physical memory. The manual write command must thus + * be issued to the NVM controller whenever the user application wishes to write + * to a NVM page for its own purposes. + * + * \subsection asfdoc_sam0_rww_eeprom_special_considerations_pagesize Logical RWW EEPROM Page Size + * As a small amount of information needs to be stored in a header before the + * content of a logical EEPROM page in memory (for use by the emulation + * service), the available data in each RWW EEPROM page is less than the total size + * of a single NVM memory page by several bytes. + * + * \subsection asfdoc_sam0_rww_eeprom_special_considerations_committing Committing of the Write Cache + * A single-page write cache is used internally to buffer data written to pages + * in order to reduce the number of physical writes required to store the user + * data, and to preserve the physical memory lifespan. As a result, it is + * important that the write cache is committed to physical memory as soon as + * possible after a BOD low power condition, to ensure that enough power is + * available to guarantee a completed write so that no data is lost. + * + * The write cache must also be manually committed to physical memory if the + * user application is to perform any NVM operations using the NVM controller + * directly. + * + * \subsection asfdoc_sam0_rww_eeprom_special_considerations_checksum RWW EEPROM Page Checksum + * For each page, a checksum function is used to verify the integrity of + * the page data. When reading the page data, using + * \ref rww_eeprom_emulator_read_page(). When its checksum is not correct, an error can be + * detected. This function can be enabled or disabled through the configuration file. + * + * \section asfdoc_sam0_rww_eeprom_extra_info Extra Information + * + * For extra information, see \ref asfdoc_sam0_rww_eeprom_extra. This includes: + * - \ref asfdoc_sam0_rww_eeprom_extra_acronyms + * - \ref asfdoc_sam0_rww_eeprom_extra_dependencies + * - \ref asfdoc_sam0_rww_eeprom_extra_errata + * - \ref asfdoc_sam0_rww_eeprom_extra_history + * + * + * \section asfdoc_sam0_rww_eeprom_examples Examples + * + * For a list of examples related to this driver, see + * \ref asfdoc_sam0_rww_eeprom_exqsg. + * + * + * \section asfdoc_sam0_rww_eeprom_api_overview API Overview + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#if !defined(__DOXYGEN__) +# define RWW_EEPROM_MAX_PAGES NVMCTRL_RWWEE_PAGES +# define RWW_EEPROM_MASTER_PAGE_NUMBER (_eeprom_instance.physical_pages - 1) +# define RWW_EEPROM_INVALID_PAGE_NUMBER 0xFF +# define RWW_EEPROM_INVALID_ROW_NUMBER (RWW_EEPROM_INVALID_PAGE_NUMBER / NVMCTRL_ROW_PAGES) +# define RWW_EEPROM_HEADER_SIZE 4 +#endif + + +/** + * \brief RWW EEPROM Logical Page in Each Row. + * + * Enum for the possible logical pages that are stored in each physical row. + * + */ +enum rwwee_logical_page_num_in_row { + /** One logical page stored in a physical row */ + RWWEE_LOGICAL_PAGE_NUM_1 = 1, + /** Two logical pages stored in a physical row */ + RWWEE_LOGICAL_PAGE_NUM_2 = 2, +}; + + +/** \name RWW EEPROM Emulator Information + * @{ + */ + +/** Emulator scheme ID, identifying the scheme used to emulated EEPROM storage. */ +#define RWW_EEPROM_EMULATOR_ID 1 + +/** Emulator major version number, identifying the emulator major version. */ +#define RWW_EEPROM_MAJOR_VERSION 1 + +/** Emulator minor version number, identifying the emulator minor version. */ +#define RWW_EEPROM_MINOR_VERSION 0 + +/** Emulator revision version number, identifying the emulator revision. */ +#define RWW_EEPROM_REVISION 0 + +/** Size of the user data portion of each logical EEPROM page, in bytes. */ +#define RWW_EEPROM_PAGE_SIZE (NVMCTRL_PAGE_SIZE - RWW_EEPROM_HEADER_SIZE) + +/** + * \brief RWW EEPROM memory parameter structure. + * + * Structure containing the memory layout parameters of the EEPROM emulator module. + */ +struct rww_eeprom_emulator_parameters { + /** Number of bytes per emulated EEPROM page */ + uint8_t page_size; + /** Number of emulated pages of EEPROM */ + uint16_t eeprom_number_of_pages; +}; + +/** @} */ + +/** \name Configuration and Initialization + * @{ + */ + +enum status_code rww_eeprom_emulator_init(void); + +void rww_eeprom_emulator_erase_memory(void); + +enum status_code rww_eeprom_emulator_get_parameters( + struct rww_eeprom_emulator_parameters *const parameters); + +/** @} */ + + +/** \name Logical RWW EEPROM Page Reading/Writing + * @{ + */ + +enum status_code rww_eeprom_emulator_commit_page_buffer(void); + +enum status_code rww_eeprom_emulator_write_page( + const uint8_t logical_page, + const uint8_t *const data); + +enum status_code rww_eeprom_emulator_read_page( + const uint8_t logical_page, + uint8_t *const data); + +/** @} */ + +/** \name Buffer RWW EEPROM Reading/Writing + * @{ + */ + +enum status_code rww_eeprom_emulator_write_buffer( + const uint16_t offset, + const uint8_t *const data, + const uint16_t length); + +enum status_code rww_eeprom_emulator_read_buffer( + const uint16_t offset, + uint8_t *const data, + const uint16_t length); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +/** @} */ + +/** + * \page asfdoc_sam0_rww_eeprom_extra Extra Information + * + * \section asfdoc_sam0_rww_eeprom_extra_acronyms Acronyms + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
AcronymDescription
EEPROMElectronically Erasable Read-Only Memory
RWWEERead While Write EEPROM
RWWRead While Write
NVMNon-Volatile Memory
+ * + * + * \section asfdoc_sam0_rww_eeprom_extra_dependencies Dependencies + * This driver has the following dependencies: + * + * - \ref asfdoc_sam0_nvm_group "Non-Volatile Memory Controller Driver" + * + * + * \section asfdoc_sam0_rww_eeprom_extra_errata Errata + * There are no errata related to this driver. + * + * + * \section asfdoc_sam0_rww_eeprom_extra_history Module History + * An overview of the module history is presented in the table below, with + * details on the enhancements and fixes made to the module since its first + * release. The current version of this corresponds to the newest version in + * the table. + * + * + * + * + * + * + * + * + *
Changelog
Initial Release
+ */ + +/** + * \page asfdoc_sam0_rww_eeprom_exqsg Examples for Emulated RWW EEPROM Service + * + * This is a list of the available Quick Start guides (QSGs) and example + * applications for \ref asfdoc_sam0_rww_eeprom_group. QSGs are simple examples with + * step-by-step instructions to configure and use this driver in a selection of + * use cases. Note that a QSG can be compiled as a standalone application or be + * added to the user application. + * + * - \subpage asfdoc_sam0_rww_eeprom_basic_use_case + * + * \page asfdoc_sam0_rww_eeprom_document_revision_history Document Revision History + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Doc. Rev.DateComments
42447B02/2016Added support for SAM L22, SAM DA1, and SAM C20/C21
42447A06/2015Initial release
+ */ + +#endif /* EEPROM_H_INCLUDED */ diff --git a/src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/ac.h b/src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/ac.h new file mode 100644 index 000000000..f82809615 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/ac.h @@ -0,0 +1,586 @@ +/** + * \file + * + * \brief Component description for AC + * + * Copyright (c) 2017 Microchip Technology Inc. + * + * \asf_license_start + * + * \page License + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the Licence at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * \asf_license_stop + * + */ + +#ifndef _SAMR34_AC_COMPONENT_ +#define _SAMR34_AC_COMPONENT_ + +/* ========================================================================== */ +/** SOFTWARE API DEFINITION FOR AC */ +/* ========================================================================== */ +/** \addtogroup SAMR34_AC Analog Comparators */ +/*@{*/ + +#define AC_U2245 +#define REV_AC 0x101 + +/* -------- AC_CTRLA : (AC Offset: 0x00) (R/W 8) Control A -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t SWRST:1; /*!< bit: 0 Software Reset */ + uint8_t ENABLE:1; /*!< bit: 1 Enable */ + uint8_t :6; /*!< bit: 2.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + uint8_t reg; /*!< Type used for register access */ +} AC_CTRLA_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define AC_CTRLA_OFFSET 0x00 /**< \brief (AC_CTRLA offset) Control A */ +#define AC_CTRLA_RESETVALUE _U_(0x00) /**< \brief (AC_CTRLA reset_value) Control A */ + +#define AC_CTRLA_SWRST_Pos 0 /**< \brief (AC_CTRLA) Software Reset */ +#define AC_CTRLA_SWRST (_U_(0x1) << AC_CTRLA_SWRST_Pos) +#define AC_CTRLA_ENABLE_Pos 1 /**< \brief (AC_CTRLA) Enable */ +#define AC_CTRLA_ENABLE (_U_(0x1) << AC_CTRLA_ENABLE_Pos) +#define AC_CTRLA_MASK _U_(0x03) /**< \brief (AC_CTRLA) MASK Register */ + +/* -------- AC_CTRLB : (AC Offset: 0x01) ( /W 8) Control B -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t START0:1; /*!< bit: 0 Comparator 0 Start Comparison */ + uint8_t START1:1; /*!< bit: 1 Comparator 1 Start Comparison */ + uint8_t :6; /*!< bit: 2.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + struct { + uint8_t START:2; /*!< bit: 0.. 1 Comparator x Start Comparison */ + uint8_t :6; /*!< bit: 2.. 7 Reserved */ + } vec; /*!< Structure used for vec access */ + uint8_t reg; /*!< Type used for register access */ +} AC_CTRLB_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define AC_CTRLB_OFFSET 0x01 /**< \brief (AC_CTRLB offset) Control B */ +#define AC_CTRLB_RESETVALUE _U_(0x00) /**< \brief (AC_CTRLB reset_value) Control B */ + +#define AC_CTRLB_START0_Pos 0 /**< \brief (AC_CTRLB) Comparator 0 Start Comparison */ +#define AC_CTRLB_START0 (_U_(1) << AC_CTRLB_START0_Pos) +#define AC_CTRLB_START1_Pos 1 /**< \brief (AC_CTRLB) Comparator 1 Start Comparison */ +#define AC_CTRLB_START1 (_U_(1) << AC_CTRLB_START1_Pos) +#define AC_CTRLB_START_Pos 0 /**< \brief (AC_CTRLB) Comparator x Start Comparison */ +#define AC_CTRLB_START_Msk (_U_(0x3) << AC_CTRLB_START_Pos) +#define AC_CTRLB_START(value) (AC_CTRLB_START_Msk & ((value) << AC_CTRLB_START_Pos)) +#define AC_CTRLB_MASK _U_(0x03) /**< \brief (AC_CTRLB) MASK Register */ + +/* -------- AC_EVCTRL : (AC Offset: 0x02) (R/W 16) Event Control -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint16_t COMPEO0:1; /*!< bit: 0 Comparator 0 Event Output Enable */ + uint16_t COMPEO1:1; /*!< bit: 1 Comparator 1 Event Output Enable */ + uint16_t :2; /*!< bit: 2.. 3 Reserved */ + uint16_t WINEO0:1; /*!< bit: 4 Window 0 Event Output Enable */ + uint16_t :3; /*!< bit: 5.. 7 Reserved */ + uint16_t COMPEI0:1; /*!< bit: 8 Comparator 0 Event Input Enable */ + uint16_t COMPEI1:1; /*!< bit: 9 Comparator 1 Event Input Enable */ + uint16_t :2; /*!< bit: 10..11 Reserved */ + uint16_t INVEI0:1; /*!< bit: 12 Comparator 0 Input Event Invert Enable */ + uint16_t INVEI1:1; /*!< bit: 13 Comparator 1 Input Event Invert Enable */ + uint16_t :2; /*!< bit: 14..15 Reserved */ + } bit; /*!< Structure used for bit access */ + struct { + uint16_t COMPEO:2; /*!< bit: 0.. 1 Comparator x Event Output Enable */ + uint16_t :2; /*!< bit: 2.. 3 Reserved */ + uint16_t WINEO:1; /*!< bit: 4 Window x Event Output Enable */ + uint16_t :3; /*!< bit: 5.. 7 Reserved */ + uint16_t COMPEI:2; /*!< bit: 8.. 9 Comparator x Event Input Enable */ + uint16_t :2; /*!< bit: 10..11 Reserved */ + uint16_t INVEI:2; /*!< bit: 12..13 Comparator x Input Event Invert Enable */ + uint16_t :2; /*!< bit: 14..15 Reserved */ + } vec; /*!< Structure used for vec access */ + uint16_t reg; /*!< Type used for register access */ +} AC_EVCTRL_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define AC_EVCTRL_OFFSET 0x02 /**< \brief (AC_EVCTRL offset) Event Control */ +#define AC_EVCTRL_RESETVALUE _U_(0x0000) /**< \brief (AC_EVCTRL reset_value) Event Control */ + +#define AC_EVCTRL_COMPEO0_Pos 0 /**< \brief (AC_EVCTRL) Comparator 0 Event Output Enable */ +#define AC_EVCTRL_COMPEO0 (_U_(1) << AC_EVCTRL_COMPEO0_Pos) +#define AC_EVCTRL_COMPEO1_Pos 1 /**< \brief (AC_EVCTRL) Comparator 1 Event Output Enable */ +#define AC_EVCTRL_COMPEO1 (_U_(1) << AC_EVCTRL_COMPEO1_Pos) +#define AC_EVCTRL_COMPEO_Pos 0 /**< \brief (AC_EVCTRL) Comparator x Event Output Enable */ +#define AC_EVCTRL_COMPEO_Msk (_U_(0x3) << AC_EVCTRL_COMPEO_Pos) +#define AC_EVCTRL_COMPEO(value) (AC_EVCTRL_COMPEO_Msk & ((value) << AC_EVCTRL_COMPEO_Pos)) +#define AC_EVCTRL_WINEO0_Pos 4 /**< \brief (AC_EVCTRL) Window 0 Event Output Enable */ +#define AC_EVCTRL_WINEO0 (_U_(1) << AC_EVCTRL_WINEO0_Pos) +#define AC_EVCTRL_WINEO_Pos 4 /**< \brief (AC_EVCTRL) Window x Event Output Enable */ +#define AC_EVCTRL_WINEO_Msk (_U_(0x1) << AC_EVCTRL_WINEO_Pos) +#define AC_EVCTRL_WINEO(value) (AC_EVCTRL_WINEO_Msk & ((value) << AC_EVCTRL_WINEO_Pos)) +#define AC_EVCTRL_COMPEI0_Pos 8 /**< \brief (AC_EVCTRL) Comparator 0 Event Input Enable */ +#define AC_EVCTRL_COMPEI0 (_U_(1) << AC_EVCTRL_COMPEI0_Pos) +#define AC_EVCTRL_COMPEI1_Pos 9 /**< \brief (AC_EVCTRL) Comparator 1 Event Input Enable */ +#define AC_EVCTRL_COMPEI1 (_U_(1) << AC_EVCTRL_COMPEI1_Pos) +#define AC_EVCTRL_COMPEI_Pos 8 /**< \brief (AC_EVCTRL) Comparator x Event Input Enable */ +#define AC_EVCTRL_COMPEI_Msk (_U_(0x3) << AC_EVCTRL_COMPEI_Pos) +#define AC_EVCTRL_COMPEI(value) (AC_EVCTRL_COMPEI_Msk & ((value) << AC_EVCTRL_COMPEI_Pos)) +#define AC_EVCTRL_INVEI0_Pos 12 /**< \brief (AC_EVCTRL) Comparator 0 Input Event Invert Enable */ +#define AC_EVCTRL_INVEI0 (_U_(1) << AC_EVCTRL_INVEI0_Pos) +#define AC_EVCTRL_INVEI1_Pos 13 /**< \brief (AC_EVCTRL) Comparator 1 Input Event Invert Enable */ +#define AC_EVCTRL_INVEI1 (_U_(1) << AC_EVCTRL_INVEI1_Pos) +#define AC_EVCTRL_INVEI_Pos 12 /**< \brief (AC_EVCTRL) Comparator x Input Event Invert Enable */ +#define AC_EVCTRL_INVEI_Msk (_U_(0x3) << AC_EVCTRL_INVEI_Pos) +#define AC_EVCTRL_INVEI(value) (AC_EVCTRL_INVEI_Msk & ((value) << AC_EVCTRL_INVEI_Pos)) +#define AC_EVCTRL_MASK _U_(0x3313) /**< \brief (AC_EVCTRL) MASK Register */ + +/* -------- AC_INTENCLR : (AC Offset: 0x04) (R/W 8) Interrupt Enable Clear -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t COMP0:1; /*!< bit: 0 Comparator 0 Interrupt Enable */ + uint8_t COMP1:1; /*!< bit: 1 Comparator 1 Interrupt Enable */ + uint8_t :2; /*!< bit: 2.. 3 Reserved */ + uint8_t WIN0:1; /*!< bit: 4 Window 0 Interrupt Enable */ + uint8_t :3; /*!< bit: 5.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + struct { + uint8_t COMP:2; /*!< bit: 0.. 1 Comparator x Interrupt Enable */ + uint8_t :2; /*!< bit: 2.. 3 Reserved */ + uint8_t WIN:1; /*!< bit: 4 Window x Interrupt Enable */ + uint8_t :3; /*!< bit: 5.. 7 Reserved */ + } vec; /*!< Structure used for vec access */ + uint8_t reg; /*!< Type used for register access */ +} AC_INTENCLR_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define AC_INTENCLR_OFFSET 0x04 /**< \brief (AC_INTENCLR offset) Interrupt Enable Clear */ +#define AC_INTENCLR_RESETVALUE _U_(0x00) /**< \brief (AC_INTENCLR reset_value) Interrupt Enable Clear */ + +#define AC_INTENCLR_COMP0_Pos 0 /**< \brief (AC_INTENCLR) Comparator 0 Interrupt Enable */ +#define AC_INTENCLR_COMP0 (_U_(1) << AC_INTENCLR_COMP0_Pos) +#define AC_INTENCLR_COMP1_Pos 1 /**< \brief (AC_INTENCLR) Comparator 1 Interrupt Enable */ +#define AC_INTENCLR_COMP1 (_U_(1) << AC_INTENCLR_COMP1_Pos) +#define AC_INTENCLR_COMP_Pos 0 /**< \brief (AC_INTENCLR) Comparator x Interrupt Enable */ +#define AC_INTENCLR_COMP_Msk (_U_(0x3) << AC_INTENCLR_COMP_Pos) +#define AC_INTENCLR_COMP(value) (AC_INTENCLR_COMP_Msk & ((value) << AC_INTENCLR_COMP_Pos)) +#define AC_INTENCLR_WIN0_Pos 4 /**< \brief (AC_INTENCLR) Window 0 Interrupt Enable */ +#define AC_INTENCLR_WIN0 (_U_(1) << AC_INTENCLR_WIN0_Pos) +#define AC_INTENCLR_WIN_Pos 4 /**< \brief (AC_INTENCLR) Window x Interrupt Enable */ +#define AC_INTENCLR_WIN_Msk (_U_(0x1) << AC_INTENCLR_WIN_Pos) +#define AC_INTENCLR_WIN(value) (AC_INTENCLR_WIN_Msk & ((value) << AC_INTENCLR_WIN_Pos)) +#define AC_INTENCLR_MASK _U_(0x13) /**< \brief (AC_INTENCLR) MASK Register */ + +/* -------- AC_INTENSET : (AC Offset: 0x05) (R/W 8) Interrupt Enable Set -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t COMP0:1; /*!< bit: 0 Comparator 0 Interrupt Enable */ + uint8_t COMP1:1; /*!< bit: 1 Comparator 1 Interrupt Enable */ + uint8_t :2; /*!< bit: 2.. 3 Reserved */ + uint8_t WIN0:1; /*!< bit: 4 Window 0 Interrupt Enable */ + uint8_t :3; /*!< bit: 5.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + struct { + uint8_t COMP:2; /*!< bit: 0.. 1 Comparator x Interrupt Enable */ + uint8_t :2; /*!< bit: 2.. 3 Reserved */ + uint8_t WIN:1; /*!< bit: 4 Window x Interrupt Enable */ + uint8_t :3; /*!< bit: 5.. 7 Reserved */ + } vec; /*!< Structure used for vec access */ + uint8_t reg; /*!< Type used for register access */ +} AC_INTENSET_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define AC_INTENSET_OFFSET 0x05 /**< \brief (AC_INTENSET offset) Interrupt Enable Set */ +#define AC_INTENSET_RESETVALUE _U_(0x00) /**< \brief (AC_INTENSET reset_value) Interrupt Enable Set */ + +#define AC_INTENSET_COMP0_Pos 0 /**< \brief (AC_INTENSET) Comparator 0 Interrupt Enable */ +#define AC_INTENSET_COMP0 (_U_(1) << AC_INTENSET_COMP0_Pos) +#define AC_INTENSET_COMP1_Pos 1 /**< \brief (AC_INTENSET) Comparator 1 Interrupt Enable */ +#define AC_INTENSET_COMP1 (_U_(1) << AC_INTENSET_COMP1_Pos) +#define AC_INTENSET_COMP_Pos 0 /**< \brief (AC_INTENSET) Comparator x Interrupt Enable */ +#define AC_INTENSET_COMP_Msk (_U_(0x3) << AC_INTENSET_COMP_Pos) +#define AC_INTENSET_COMP(value) (AC_INTENSET_COMP_Msk & ((value) << AC_INTENSET_COMP_Pos)) +#define AC_INTENSET_WIN0_Pos 4 /**< \brief (AC_INTENSET) Window 0 Interrupt Enable */ +#define AC_INTENSET_WIN0 (_U_(1) << AC_INTENSET_WIN0_Pos) +#define AC_INTENSET_WIN_Pos 4 /**< \brief (AC_INTENSET) Window x Interrupt Enable */ +#define AC_INTENSET_WIN_Msk (_U_(0x1) << AC_INTENSET_WIN_Pos) +#define AC_INTENSET_WIN(value) (AC_INTENSET_WIN_Msk & ((value) << AC_INTENSET_WIN_Pos)) +#define AC_INTENSET_MASK _U_(0x13) /**< \brief (AC_INTENSET) MASK Register */ + +/* -------- AC_INTFLAG : (AC Offset: 0x06) (R/W 8) Interrupt Flag Status and Clear -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { // __I to avoid read-modify-write on write-to-clear register + struct { + __I uint8_t COMP0:1; /*!< bit: 0 Comparator 0 */ + __I uint8_t COMP1:1; /*!< bit: 1 Comparator 1 */ + __I uint8_t :2; /*!< bit: 2.. 3 Reserved */ + __I uint8_t WIN0:1; /*!< bit: 4 Window 0 */ + __I uint8_t :3; /*!< bit: 5.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + struct { + __I uint8_t COMP:2; /*!< bit: 0.. 1 Comparator x */ + __I uint8_t :2; /*!< bit: 2.. 3 Reserved */ + __I uint8_t WIN:1; /*!< bit: 4 Window x */ + __I uint8_t :3; /*!< bit: 5.. 7 Reserved */ + } vec; /*!< Structure used for vec access */ + uint8_t reg; /*!< Type used for register access */ +} AC_INTFLAG_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define AC_INTFLAG_OFFSET 0x06 /**< \brief (AC_INTFLAG offset) Interrupt Flag Status and Clear */ +#define AC_INTFLAG_RESETVALUE _U_(0x00) /**< \brief (AC_INTFLAG reset_value) Interrupt Flag Status and Clear */ + +#define AC_INTFLAG_COMP0_Pos 0 /**< \brief (AC_INTFLAG) Comparator 0 */ +#define AC_INTFLAG_COMP0 (_U_(1) << AC_INTFLAG_COMP0_Pos) +#define AC_INTFLAG_COMP1_Pos 1 /**< \brief (AC_INTFLAG) Comparator 1 */ +#define AC_INTFLAG_COMP1 (_U_(1) << AC_INTFLAG_COMP1_Pos) +#define AC_INTFLAG_COMP_Pos 0 /**< \brief (AC_INTFLAG) Comparator x */ +#define AC_INTFLAG_COMP_Msk (_U_(0x3) << AC_INTFLAG_COMP_Pos) +#define AC_INTFLAG_COMP(value) (AC_INTFLAG_COMP_Msk & ((value) << AC_INTFLAG_COMP_Pos)) +#define AC_INTFLAG_WIN0_Pos 4 /**< \brief (AC_INTFLAG) Window 0 */ +#define AC_INTFLAG_WIN0 (_U_(1) << AC_INTFLAG_WIN0_Pos) +#define AC_INTFLAG_WIN_Pos 4 /**< \brief (AC_INTFLAG) Window x */ +#define AC_INTFLAG_WIN_Msk (_U_(0x1) << AC_INTFLAG_WIN_Pos) +#define AC_INTFLAG_WIN(value) (AC_INTFLAG_WIN_Msk & ((value) << AC_INTFLAG_WIN_Pos)) +#define AC_INTFLAG_MASK _U_(0x13) /**< \brief (AC_INTFLAG) MASK Register */ + +/* -------- AC_STATUSA : (AC Offset: 0x07) (R/ 8) Status A -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t STATE0:1; /*!< bit: 0 Comparator 0 Current State */ + uint8_t STATE1:1; /*!< bit: 1 Comparator 1 Current State */ + uint8_t :2; /*!< bit: 2.. 3 Reserved */ + uint8_t WSTATE0:2; /*!< bit: 4.. 5 Window 0 Current State */ + uint8_t :2; /*!< bit: 6.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + struct { + uint8_t STATE:2; /*!< bit: 0.. 1 Comparator x Current State */ + uint8_t :6; /*!< bit: 2.. 7 Reserved */ + } vec; /*!< Structure used for vec access */ + uint8_t reg; /*!< Type used for register access */ +} AC_STATUSA_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define AC_STATUSA_OFFSET 0x07 /**< \brief (AC_STATUSA offset) Status A */ +#define AC_STATUSA_RESETVALUE _U_(0x00) /**< \brief (AC_STATUSA reset_value) Status A */ + +#define AC_STATUSA_STATE0_Pos 0 /**< \brief (AC_STATUSA) Comparator 0 Current State */ +#define AC_STATUSA_STATE0 (_U_(1) << AC_STATUSA_STATE0_Pos) +#define AC_STATUSA_STATE1_Pos 1 /**< \brief (AC_STATUSA) Comparator 1 Current State */ +#define AC_STATUSA_STATE1 (_U_(1) << AC_STATUSA_STATE1_Pos) +#define AC_STATUSA_STATE_Pos 0 /**< \brief (AC_STATUSA) Comparator x Current State */ +#define AC_STATUSA_STATE_Msk (_U_(0x3) << AC_STATUSA_STATE_Pos) +#define AC_STATUSA_STATE(value) (AC_STATUSA_STATE_Msk & ((value) << AC_STATUSA_STATE_Pos)) +#define AC_STATUSA_WSTATE0_Pos 4 /**< \brief (AC_STATUSA) Window 0 Current State */ +#define AC_STATUSA_WSTATE0_Msk (_U_(0x3) << AC_STATUSA_WSTATE0_Pos) +#define AC_STATUSA_WSTATE0(value) (AC_STATUSA_WSTATE0_Msk & ((value) << AC_STATUSA_WSTATE0_Pos)) +#define AC_STATUSA_WSTATE0_ABOVE_Val _U_(0x0) /**< \brief (AC_STATUSA) Signal is above window */ +#define AC_STATUSA_WSTATE0_INSIDE_Val _U_(0x1) /**< \brief (AC_STATUSA) Signal is inside window */ +#define AC_STATUSA_WSTATE0_BELOW_Val _U_(0x2) /**< \brief (AC_STATUSA) Signal is below window */ +#define AC_STATUSA_WSTATE0_ABOVE (AC_STATUSA_WSTATE0_ABOVE_Val << AC_STATUSA_WSTATE0_Pos) +#define AC_STATUSA_WSTATE0_INSIDE (AC_STATUSA_WSTATE0_INSIDE_Val << AC_STATUSA_WSTATE0_Pos) +#define AC_STATUSA_WSTATE0_BELOW (AC_STATUSA_WSTATE0_BELOW_Val << AC_STATUSA_WSTATE0_Pos) +#define AC_STATUSA_MASK _U_(0x33) /**< \brief (AC_STATUSA) MASK Register */ + +/* -------- AC_STATUSB : (AC Offset: 0x08) (R/ 8) Status B -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t READY0:1; /*!< bit: 0 Comparator 0 Ready */ + uint8_t READY1:1; /*!< bit: 1 Comparator 1 Ready */ + uint8_t :6; /*!< bit: 2.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + struct { + uint8_t READY:2; /*!< bit: 0.. 1 Comparator x Ready */ + uint8_t :6; /*!< bit: 2.. 7 Reserved */ + } vec; /*!< Structure used for vec access */ + uint8_t reg; /*!< Type used for register access */ +} AC_STATUSB_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define AC_STATUSB_OFFSET 0x08 /**< \brief (AC_STATUSB offset) Status B */ +#define AC_STATUSB_RESETVALUE _U_(0x00) /**< \brief (AC_STATUSB reset_value) Status B */ + +#define AC_STATUSB_READY0_Pos 0 /**< \brief (AC_STATUSB) Comparator 0 Ready */ +#define AC_STATUSB_READY0 (_U_(1) << AC_STATUSB_READY0_Pos) +#define AC_STATUSB_READY1_Pos 1 /**< \brief (AC_STATUSB) Comparator 1 Ready */ +#define AC_STATUSB_READY1 (_U_(1) << AC_STATUSB_READY1_Pos) +#define AC_STATUSB_READY_Pos 0 /**< \brief (AC_STATUSB) Comparator x Ready */ +#define AC_STATUSB_READY_Msk (_U_(0x3) << AC_STATUSB_READY_Pos) +#define AC_STATUSB_READY(value) (AC_STATUSB_READY_Msk & ((value) << AC_STATUSB_READY_Pos)) +#define AC_STATUSB_MASK _U_(0x03) /**< \brief (AC_STATUSB) MASK Register */ + +/* -------- AC_DBGCTRL : (AC Offset: 0x09) (R/W 8) Debug Control -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t DBGRUN:1; /*!< bit: 0 Debug Run */ + uint8_t :7; /*!< bit: 1.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + uint8_t reg; /*!< Type used for register access */ +} AC_DBGCTRL_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define AC_DBGCTRL_OFFSET 0x09 /**< \brief (AC_DBGCTRL offset) Debug Control */ +#define AC_DBGCTRL_RESETVALUE _U_(0x00) /**< \brief (AC_DBGCTRL reset_value) Debug Control */ + +#define AC_DBGCTRL_DBGRUN_Pos 0 /**< \brief (AC_DBGCTRL) Debug Run */ +#define AC_DBGCTRL_DBGRUN (_U_(0x1) << AC_DBGCTRL_DBGRUN_Pos) +#define AC_DBGCTRL_MASK _U_(0x01) /**< \brief (AC_DBGCTRL) MASK Register */ + +/* -------- AC_WINCTRL : (AC Offset: 0x0A) (R/W 8) Window Control -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t WEN0:1; /*!< bit: 0 Window 0 Mode Enable */ + uint8_t WINTSEL0:2; /*!< bit: 1.. 2 Window 0 Interrupt Selection */ + uint8_t :5; /*!< bit: 3.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + uint8_t reg; /*!< Type used for register access */ +} AC_WINCTRL_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define AC_WINCTRL_OFFSET 0x0A /**< \brief (AC_WINCTRL offset) Window Control */ +#define AC_WINCTRL_RESETVALUE _U_(0x00) /**< \brief (AC_WINCTRL reset_value) Window Control */ + +#define AC_WINCTRL_WEN0_Pos 0 /**< \brief (AC_WINCTRL) Window 0 Mode Enable */ +#define AC_WINCTRL_WEN0 (_U_(0x1) << AC_WINCTRL_WEN0_Pos) +#define AC_WINCTRL_WINTSEL0_Pos 1 /**< \brief (AC_WINCTRL) Window 0 Interrupt Selection */ +#define AC_WINCTRL_WINTSEL0_Msk (_U_(0x3) << AC_WINCTRL_WINTSEL0_Pos) +#define AC_WINCTRL_WINTSEL0(value) (AC_WINCTRL_WINTSEL0_Msk & ((value) << AC_WINCTRL_WINTSEL0_Pos)) +#define AC_WINCTRL_WINTSEL0_ABOVE_Val _U_(0x0) /**< \brief (AC_WINCTRL) Interrupt on signal above window */ +#define AC_WINCTRL_WINTSEL0_INSIDE_Val _U_(0x1) /**< \brief (AC_WINCTRL) Interrupt on signal inside window */ +#define AC_WINCTRL_WINTSEL0_BELOW_Val _U_(0x2) /**< \brief (AC_WINCTRL) Interrupt on signal below window */ +#define AC_WINCTRL_WINTSEL0_OUTSIDE_Val _U_(0x3) /**< \brief (AC_WINCTRL) Interrupt on signal outside window */ +#define AC_WINCTRL_WINTSEL0_ABOVE (AC_WINCTRL_WINTSEL0_ABOVE_Val << AC_WINCTRL_WINTSEL0_Pos) +#define AC_WINCTRL_WINTSEL0_INSIDE (AC_WINCTRL_WINTSEL0_INSIDE_Val << AC_WINCTRL_WINTSEL0_Pos) +#define AC_WINCTRL_WINTSEL0_BELOW (AC_WINCTRL_WINTSEL0_BELOW_Val << AC_WINCTRL_WINTSEL0_Pos) +#define AC_WINCTRL_WINTSEL0_OUTSIDE (AC_WINCTRL_WINTSEL0_OUTSIDE_Val << AC_WINCTRL_WINTSEL0_Pos) +#define AC_WINCTRL_MASK _U_(0x07) /**< \brief (AC_WINCTRL) MASK Register */ + +/* -------- AC_SCALER : (AC Offset: 0x0C) (R/W 8) Scaler n -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t VALUE:6; /*!< bit: 0.. 5 Scaler Value */ + uint8_t :2; /*!< bit: 6.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + uint8_t reg; /*!< Type used for register access */ +} AC_SCALER_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define AC_SCALER_OFFSET 0x0C /**< \brief (AC_SCALER offset) Scaler n */ +#define AC_SCALER_RESETVALUE _U_(0x00) /**< \brief (AC_SCALER reset_value) Scaler n */ + +#define AC_SCALER_VALUE_Pos 0 /**< \brief (AC_SCALER) Scaler Value */ +#define AC_SCALER_VALUE_Msk (_U_(0x3F) << AC_SCALER_VALUE_Pos) +#define AC_SCALER_VALUE(value) (AC_SCALER_VALUE_Msk & ((value) << AC_SCALER_VALUE_Pos)) +#define AC_SCALER_MASK _U_(0x3F) /**< \brief (AC_SCALER) MASK Register */ + +/* -------- AC_COMPCTRL : (AC Offset: 0x10) (R/W 32) Comparator Control n -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint32_t :1; /*!< bit: 0 Reserved */ + uint32_t ENABLE:1; /*!< bit: 1 Enable */ + uint32_t SINGLE:1; /*!< bit: 2 Single-Shot Mode */ + uint32_t INTSEL:2; /*!< bit: 3.. 4 Interrupt Selection */ + uint32_t :1; /*!< bit: 5 Reserved */ + uint32_t RUNSTDBY:1; /*!< bit: 6 Run in Standby */ + uint32_t :1; /*!< bit: 7 Reserved */ + uint32_t MUXNEG:3; /*!< bit: 8..10 Negative Input Mux Selection */ + uint32_t :1; /*!< bit: 11 Reserved */ + uint32_t MUXPOS:3; /*!< bit: 12..14 Positive Input Mux Selection */ + uint32_t SWAP:1; /*!< bit: 15 Swap Inputs and Invert */ + uint32_t SPEED:2; /*!< bit: 16..17 Speed Selection */ + uint32_t :1; /*!< bit: 18 Reserved */ + uint32_t HYSTEN:1; /*!< bit: 19 Hysteresis Enable */ + uint32_t HYST:2; /*!< bit: 20..21 Hysteresis Level */ + uint32_t :2; /*!< bit: 22..23 Reserved */ + uint32_t FLEN:3; /*!< bit: 24..26 Filter Length */ + uint32_t :1; /*!< bit: 27 Reserved */ + uint32_t OUT:2; /*!< bit: 28..29 Output */ + uint32_t :2; /*!< bit: 30..31 Reserved */ + } bit; /*!< Structure used for bit access */ + uint32_t reg; /*!< Type used for register access */ +} AC_COMPCTRL_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define AC_COMPCTRL_OFFSET 0x10 /**< \brief (AC_COMPCTRL offset) Comparator Control n */ +#define AC_COMPCTRL_RESETVALUE _U_(0x00000000) /**< \brief (AC_COMPCTRL reset_value) Comparator Control n */ + +#define AC_COMPCTRL_ENABLE_Pos 1 /**< \brief (AC_COMPCTRL) Enable */ +#define AC_COMPCTRL_ENABLE (_U_(0x1) << AC_COMPCTRL_ENABLE_Pos) +#define AC_COMPCTRL_SINGLE_Pos 2 /**< \brief (AC_COMPCTRL) Single-Shot Mode */ +#define AC_COMPCTRL_SINGLE (_U_(0x1) << AC_COMPCTRL_SINGLE_Pos) +#define AC_COMPCTRL_INTSEL_Pos 3 /**< \brief (AC_COMPCTRL) Interrupt Selection */ +#define AC_COMPCTRL_INTSEL_Msk (_U_(0x3) << AC_COMPCTRL_INTSEL_Pos) +#define AC_COMPCTRL_INTSEL(value) (AC_COMPCTRL_INTSEL_Msk & ((value) << AC_COMPCTRL_INTSEL_Pos)) +#define AC_COMPCTRL_INTSEL_TOGGLE_Val _U_(0x0) /**< \brief (AC_COMPCTRL) Interrupt on comparator output toggle */ +#define AC_COMPCTRL_INTSEL_RISING_Val _U_(0x1) /**< \brief (AC_COMPCTRL) Interrupt on comparator output rising */ +#define AC_COMPCTRL_INTSEL_FALLING_Val _U_(0x2) /**< \brief (AC_COMPCTRL) Interrupt on comparator output falling */ +#define AC_COMPCTRL_INTSEL_EOC_Val _U_(0x3) /**< \brief (AC_COMPCTRL) Interrupt on end of comparison (single-shot mode only) */ +#define AC_COMPCTRL_INTSEL_TOGGLE (AC_COMPCTRL_INTSEL_TOGGLE_Val << AC_COMPCTRL_INTSEL_Pos) +#define AC_COMPCTRL_INTSEL_RISING (AC_COMPCTRL_INTSEL_RISING_Val << AC_COMPCTRL_INTSEL_Pos) +#define AC_COMPCTRL_INTSEL_FALLING (AC_COMPCTRL_INTSEL_FALLING_Val << AC_COMPCTRL_INTSEL_Pos) +#define AC_COMPCTRL_INTSEL_EOC (AC_COMPCTRL_INTSEL_EOC_Val << AC_COMPCTRL_INTSEL_Pos) +#define AC_COMPCTRL_RUNSTDBY_Pos 6 /**< \brief (AC_COMPCTRL) Run in Standby */ +#define AC_COMPCTRL_RUNSTDBY (_U_(0x1) << AC_COMPCTRL_RUNSTDBY_Pos) +#define AC_COMPCTRL_MUXNEG_Pos 8 /**< \brief (AC_COMPCTRL) Negative Input Mux Selection */ +#define AC_COMPCTRL_MUXNEG_Msk (_U_(0x7) << AC_COMPCTRL_MUXNEG_Pos) +#define AC_COMPCTRL_MUXNEG(value) (AC_COMPCTRL_MUXNEG_Msk & ((value) << AC_COMPCTRL_MUXNEG_Pos)) +#define AC_COMPCTRL_MUXNEG_PIN0_Val _U_(0x0) /**< \brief (AC_COMPCTRL) I/O pin 0 */ +#define AC_COMPCTRL_MUXNEG_PIN1_Val _U_(0x1) /**< \brief (AC_COMPCTRL) I/O pin 1 */ +#define AC_COMPCTRL_MUXNEG_PIN2_Val _U_(0x2) /**< \brief (AC_COMPCTRL) I/O pin 2 */ +#define AC_COMPCTRL_MUXNEG_PIN3_Val _U_(0x3) /**< \brief (AC_COMPCTRL) I/O pin 3 */ +#define AC_COMPCTRL_MUXNEG_GND_Val _U_(0x4) /**< \brief (AC_COMPCTRL) Ground */ +#define AC_COMPCTRL_MUXNEG_VSCALE_Val _U_(0x5) /**< \brief (AC_COMPCTRL) VDD scaler */ +#define AC_COMPCTRL_MUXNEG_BANDGAP_Val _U_(0x6) /**< \brief (AC_COMPCTRL) Internal bandgap voltage */ +#define AC_COMPCTRL_MUXNEG_DAC_Val _U_(0x7) /**< \brief (AC_COMPCTRL) DAC output */ +#define AC_COMPCTRL_MUXNEG_PIN0 (AC_COMPCTRL_MUXNEG_PIN0_Val << AC_COMPCTRL_MUXNEG_Pos) +#define AC_COMPCTRL_MUXNEG_PIN1 (AC_COMPCTRL_MUXNEG_PIN1_Val << AC_COMPCTRL_MUXNEG_Pos) +#define AC_COMPCTRL_MUXNEG_PIN2 (AC_COMPCTRL_MUXNEG_PIN2_Val << AC_COMPCTRL_MUXNEG_Pos) +#define AC_COMPCTRL_MUXNEG_PIN3 (AC_COMPCTRL_MUXNEG_PIN3_Val << AC_COMPCTRL_MUXNEG_Pos) +#define AC_COMPCTRL_MUXNEG_GND (AC_COMPCTRL_MUXNEG_GND_Val << AC_COMPCTRL_MUXNEG_Pos) +#define AC_COMPCTRL_MUXNEG_VSCALE (AC_COMPCTRL_MUXNEG_VSCALE_Val << AC_COMPCTRL_MUXNEG_Pos) +#define AC_COMPCTRL_MUXNEG_BANDGAP (AC_COMPCTRL_MUXNEG_BANDGAP_Val << AC_COMPCTRL_MUXNEG_Pos) +#define AC_COMPCTRL_MUXNEG_DAC (AC_COMPCTRL_MUXNEG_DAC_Val << AC_COMPCTRL_MUXNEG_Pos) +#define AC_COMPCTRL_MUXPOS_Pos 12 /**< \brief (AC_COMPCTRL) Positive Input Mux Selection */ +#define AC_COMPCTRL_MUXPOS_Msk (_U_(0x7) << AC_COMPCTRL_MUXPOS_Pos) +#define AC_COMPCTRL_MUXPOS(value) (AC_COMPCTRL_MUXPOS_Msk & ((value) << AC_COMPCTRL_MUXPOS_Pos)) +#define AC_COMPCTRL_MUXPOS_PIN0_Val _U_(0x0) /**< \brief (AC_COMPCTRL) I/O pin 0 */ +#define AC_COMPCTRL_MUXPOS_PIN1_Val _U_(0x1) /**< \brief (AC_COMPCTRL) I/O pin 1 */ +#define AC_COMPCTRL_MUXPOS_PIN2_Val _U_(0x2) /**< \brief (AC_COMPCTRL) I/O pin 2 */ +#define AC_COMPCTRL_MUXPOS_PIN3_Val _U_(0x3) /**< \brief (AC_COMPCTRL) I/O pin 3 */ +#define AC_COMPCTRL_MUXPOS_VSCALE_Val _U_(0x4) /**< \brief (AC_COMPCTRL) VDD Scaler */ +#define AC_COMPCTRL_MUXPOS_PIN0 (AC_COMPCTRL_MUXPOS_PIN0_Val << AC_COMPCTRL_MUXPOS_Pos) +#define AC_COMPCTRL_MUXPOS_PIN1 (AC_COMPCTRL_MUXPOS_PIN1_Val << AC_COMPCTRL_MUXPOS_Pos) +#define AC_COMPCTRL_MUXPOS_PIN2 (AC_COMPCTRL_MUXPOS_PIN2_Val << AC_COMPCTRL_MUXPOS_Pos) +#define AC_COMPCTRL_MUXPOS_PIN3 (AC_COMPCTRL_MUXPOS_PIN3_Val << AC_COMPCTRL_MUXPOS_Pos) +#define AC_COMPCTRL_MUXPOS_VSCALE (AC_COMPCTRL_MUXPOS_VSCALE_Val << AC_COMPCTRL_MUXPOS_Pos) +#define AC_COMPCTRL_SWAP_Pos 15 /**< \brief (AC_COMPCTRL) Swap Inputs and Invert */ +#define AC_COMPCTRL_SWAP (_U_(0x1) << AC_COMPCTRL_SWAP_Pos) +#define AC_COMPCTRL_SPEED_Pos 16 /**< \brief (AC_COMPCTRL) Speed Selection */ +#define AC_COMPCTRL_SPEED_Msk (_U_(0x3) << AC_COMPCTRL_SPEED_Pos) +#define AC_COMPCTRL_SPEED(value) (AC_COMPCTRL_SPEED_Msk & ((value) << AC_COMPCTRL_SPEED_Pos)) +#define AC_COMPCTRL_SPEED_LOW_Val _U_(0x0) /**< \brief (AC_COMPCTRL) Low speed */ +#define AC_COMPCTRL_SPEED_MEDLOW_Val _U_(0x1) /**< \brief (AC_COMPCTRL) Medium low speed */ +#define AC_COMPCTRL_SPEED_MEDHIGH_Val _U_(0x2) /**< \brief (AC_COMPCTRL) Medium high speed */ +#define AC_COMPCTRL_SPEED_HIGH_Val _U_(0x3) /**< \brief (AC_COMPCTRL) High speed */ +#define AC_COMPCTRL_SPEED_LOW (AC_COMPCTRL_SPEED_LOW_Val << AC_COMPCTRL_SPEED_Pos) +#define AC_COMPCTRL_SPEED_MEDLOW (AC_COMPCTRL_SPEED_MEDLOW_Val << AC_COMPCTRL_SPEED_Pos) +#define AC_COMPCTRL_SPEED_MEDHIGH (AC_COMPCTRL_SPEED_MEDHIGH_Val << AC_COMPCTRL_SPEED_Pos) +#define AC_COMPCTRL_SPEED_HIGH (AC_COMPCTRL_SPEED_HIGH_Val << AC_COMPCTRL_SPEED_Pos) +#define AC_COMPCTRL_HYSTEN_Pos 19 /**< \brief (AC_COMPCTRL) Hysteresis Enable */ +#define AC_COMPCTRL_HYSTEN (_U_(0x1) << AC_COMPCTRL_HYSTEN_Pos) +#define AC_COMPCTRL_HYST_Pos 20 /**< \brief (AC_COMPCTRL) Hysteresis Level */ +#define AC_COMPCTRL_HYST_Msk (_U_(0x3) << AC_COMPCTRL_HYST_Pos) +#define AC_COMPCTRL_HYST(value) (AC_COMPCTRL_HYST_Msk & ((value) << AC_COMPCTRL_HYST_Pos)) +#define AC_COMPCTRL_HYST_HYST50_Val _U_(0x0) /**< \brief (AC_COMPCTRL) 50mV */ +#define AC_COMPCTRL_HYST_HYST70_Val _U_(0x1) /**< \brief (AC_COMPCTRL) 70mV */ +#define AC_COMPCTRL_HYST_HYST90_Val _U_(0x2) /**< \brief (AC_COMPCTRL) 90mV */ +#define AC_COMPCTRL_HYST_HYST110_Val _U_(0x3) /**< \brief (AC_COMPCTRL) 110mV */ +#define AC_COMPCTRL_HYST_HYST50 (AC_COMPCTRL_HYST_HYST50_Val << AC_COMPCTRL_HYST_Pos) +#define AC_COMPCTRL_HYST_HYST70 (AC_COMPCTRL_HYST_HYST70_Val << AC_COMPCTRL_HYST_Pos) +#define AC_COMPCTRL_HYST_HYST90 (AC_COMPCTRL_HYST_HYST90_Val << AC_COMPCTRL_HYST_Pos) +#define AC_COMPCTRL_HYST_HYST110 (AC_COMPCTRL_HYST_HYST110_Val << AC_COMPCTRL_HYST_Pos) +#define AC_COMPCTRL_FLEN_Pos 24 /**< \brief (AC_COMPCTRL) Filter Length */ +#define AC_COMPCTRL_FLEN_Msk (_U_(0x7) << AC_COMPCTRL_FLEN_Pos) +#define AC_COMPCTRL_FLEN(value) (AC_COMPCTRL_FLEN_Msk & ((value) << AC_COMPCTRL_FLEN_Pos)) +#define AC_COMPCTRL_FLEN_OFF_Val _U_(0x0) /**< \brief (AC_COMPCTRL) No filtering */ +#define AC_COMPCTRL_FLEN_MAJ3_Val _U_(0x1) /**< \brief (AC_COMPCTRL) 3-bit majority function (2 of 3) */ +#define AC_COMPCTRL_FLEN_MAJ5_Val _U_(0x2) /**< \brief (AC_COMPCTRL) 5-bit majority function (3 of 5) */ +#define AC_COMPCTRL_FLEN_OFF (AC_COMPCTRL_FLEN_OFF_Val << AC_COMPCTRL_FLEN_Pos) +#define AC_COMPCTRL_FLEN_MAJ3 (AC_COMPCTRL_FLEN_MAJ3_Val << AC_COMPCTRL_FLEN_Pos) +#define AC_COMPCTRL_FLEN_MAJ5 (AC_COMPCTRL_FLEN_MAJ5_Val << AC_COMPCTRL_FLEN_Pos) +#define AC_COMPCTRL_OUT_Pos 28 /**< \brief (AC_COMPCTRL) Output */ +#define AC_COMPCTRL_OUT_Msk (_U_(0x3) << AC_COMPCTRL_OUT_Pos) +#define AC_COMPCTRL_OUT(value) (AC_COMPCTRL_OUT_Msk & ((value) << AC_COMPCTRL_OUT_Pos)) +#define AC_COMPCTRL_OUT_OFF_Val _U_(0x0) /**< \brief (AC_COMPCTRL) The output of COMPn is not routed to the COMPn I/O port */ +#define AC_COMPCTRL_OUT_ASYNC_Val _U_(0x1) /**< \brief (AC_COMPCTRL) The asynchronous output of COMPn is routed to the COMPn I/O port */ +#define AC_COMPCTRL_OUT_SYNC_Val _U_(0x2) /**< \brief (AC_COMPCTRL) The synchronous output (including filtering) of COMPn is routed to the COMPn I/O port */ +#define AC_COMPCTRL_OUT_OFF (AC_COMPCTRL_OUT_OFF_Val << AC_COMPCTRL_OUT_Pos) +#define AC_COMPCTRL_OUT_ASYNC (AC_COMPCTRL_OUT_ASYNC_Val << AC_COMPCTRL_OUT_Pos) +#define AC_COMPCTRL_OUT_SYNC (AC_COMPCTRL_OUT_SYNC_Val << AC_COMPCTRL_OUT_Pos) +#define AC_COMPCTRL_MASK _U_(0x373BF75E) /**< \brief (AC_COMPCTRL) MASK Register */ + +/* -------- AC_SYNCBUSY : (AC Offset: 0x20) (R/ 32) Synchronization Busy -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint32_t SWRST:1; /*!< bit: 0 Software Reset Synchronization Busy */ + uint32_t ENABLE:1; /*!< bit: 1 Enable Synchronization Busy */ + uint32_t WINCTRL:1; /*!< bit: 2 WINCTRL Synchronization Busy */ + uint32_t COMPCTRL0:1; /*!< bit: 3 COMPCTRL 0 Synchronization Busy */ + uint32_t COMPCTRL1:1; /*!< bit: 4 COMPCTRL 1 Synchronization Busy */ + uint32_t :27; /*!< bit: 5..31 Reserved */ + } bit; /*!< Structure used for bit access */ + struct { + uint32_t :3; /*!< bit: 0.. 2 Reserved */ + uint32_t COMPCTRL:2; /*!< bit: 3.. 4 COMPCTRL x Synchronization Busy */ + uint32_t :27; /*!< bit: 5..31 Reserved */ + } vec; /*!< Structure used for vec access */ + uint32_t reg; /*!< Type used for register access */ +} AC_SYNCBUSY_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define AC_SYNCBUSY_OFFSET 0x20 /**< \brief (AC_SYNCBUSY offset) Synchronization Busy */ +#define AC_SYNCBUSY_RESETVALUE _U_(0x00000000) /**< \brief (AC_SYNCBUSY reset_value) Synchronization Busy */ + +#define AC_SYNCBUSY_SWRST_Pos 0 /**< \brief (AC_SYNCBUSY) Software Reset Synchronization Busy */ +#define AC_SYNCBUSY_SWRST (_U_(0x1) << AC_SYNCBUSY_SWRST_Pos) +#define AC_SYNCBUSY_ENABLE_Pos 1 /**< \brief (AC_SYNCBUSY) Enable Synchronization Busy */ +#define AC_SYNCBUSY_ENABLE (_U_(0x1) << AC_SYNCBUSY_ENABLE_Pos) +#define AC_SYNCBUSY_WINCTRL_Pos 2 /**< \brief (AC_SYNCBUSY) WINCTRL Synchronization Busy */ +#define AC_SYNCBUSY_WINCTRL (_U_(0x1) << AC_SYNCBUSY_WINCTRL_Pos) +#define AC_SYNCBUSY_COMPCTRL0_Pos 3 /**< \brief (AC_SYNCBUSY) COMPCTRL 0 Synchronization Busy */ +#define AC_SYNCBUSY_COMPCTRL0 (_U_(1) << AC_SYNCBUSY_COMPCTRL0_Pos) +#define AC_SYNCBUSY_COMPCTRL1_Pos 4 /**< \brief (AC_SYNCBUSY) COMPCTRL 1 Synchronization Busy */ +#define AC_SYNCBUSY_COMPCTRL1 (_U_(1) << AC_SYNCBUSY_COMPCTRL1_Pos) +#define AC_SYNCBUSY_COMPCTRL_Pos 3 /**< \brief (AC_SYNCBUSY) COMPCTRL x Synchronization Busy */ +#define AC_SYNCBUSY_COMPCTRL_Msk (_U_(0x3) << AC_SYNCBUSY_COMPCTRL_Pos) +#define AC_SYNCBUSY_COMPCTRL(value) (AC_SYNCBUSY_COMPCTRL_Msk & ((value) << AC_SYNCBUSY_COMPCTRL_Pos)) +#define AC_SYNCBUSY_MASK _U_(0x0000001F) /**< \brief (AC_SYNCBUSY) MASK Register */ + +/** \brief AC hardware registers */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef struct { + __IO AC_CTRLA_Type CTRLA; /**< \brief Offset: 0x00 (R/W 8) Control A */ + __O AC_CTRLB_Type CTRLB; /**< \brief Offset: 0x01 ( /W 8) Control B */ + __IO AC_EVCTRL_Type EVCTRL; /**< \brief Offset: 0x02 (R/W 16) Event Control */ + __IO AC_INTENCLR_Type INTENCLR; /**< \brief Offset: 0x04 (R/W 8) Interrupt Enable Clear */ + __IO AC_INTENSET_Type INTENSET; /**< \brief Offset: 0x05 (R/W 8) Interrupt Enable Set */ + __IO AC_INTFLAG_Type INTFLAG; /**< \brief Offset: 0x06 (R/W 8) Interrupt Flag Status and Clear */ + __I AC_STATUSA_Type STATUSA; /**< \brief Offset: 0x07 (R/ 8) Status A */ + __I AC_STATUSB_Type STATUSB; /**< \brief Offset: 0x08 (R/ 8) Status B */ + __IO AC_DBGCTRL_Type DBGCTRL; /**< \brief Offset: 0x09 (R/W 8) Debug Control */ + __IO AC_WINCTRL_Type WINCTRL; /**< \brief Offset: 0x0A (R/W 8) Window Control */ + RoReg8 Reserved1[0x1]; + __IO AC_SCALER_Type SCALER[2]; /**< \brief Offset: 0x0C (R/W 8) Scaler n */ + RoReg8 Reserved2[0x2]; + __IO AC_COMPCTRL_Type COMPCTRL[2]; /**< \brief Offset: 0x10 (R/W 32) Comparator Control n */ + RoReg8 Reserved3[0x8]; + __I AC_SYNCBUSY_Type SYNCBUSY; /**< \brief Offset: 0x20 (R/ 32) Synchronization Busy */ +} Ac; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +/*@}*/ + +#endif /* _SAMR34_AC_COMPONENT_ */ diff --git a/src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/adc.h b/src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/adc.h new file mode 100644 index 000000000..a7f23d940 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/adc.h @@ -0,0 +1,728 @@ +/** + * \file + * + * \brief Component description for ADC + * + * Copyright (c) 2017 Microchip Technology Inc. + * + * \asf_license_start + * + * \page License + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the Licence at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * \asf_license_stop + * + */ + +#ifndef _SAMR34_ADC_COMPONENT_ +#define _SAMR34_ADC_COMPONENT_ + +/* ========================================================================== */ +/** SOFTWARE API DEFINITION FOR ADC */ +/* ========================================================================== */ +/** \addtogroup SAMR34_ADC Analog Digital Converter */ +/*@{*/ + +#define ADC_U2247 +#define REV_ADC 0x111 + +/* -------- ADC_CTRLA : (ADC Offset: 0x00) (R/W 8) Control A -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t SWRST:1; /*!< bit: 0 Software Reset */ + uint8_t ENABLE:1; /*!< bit: 1 Enable */ + uint8_t :4; /*!< bit: 2.. 5 Reserved */ + uint8_t RUNSTDBY:1; /*!< bit: 6 Run during Standby */ + uint8_t ONDEMAND:1; /*!< bit: 7 On Demand Control */ + } bit; /*!< Structure used for bit access */ + uint8_t reg; /*!< Type used for register access */ +} ADC_CTRLA_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define ADC_CTRLA_OFFSET 0x00 /**< \brief (ADC_CTRLA offset) Control A */ +#define ADC_CTRLA_RESETVALUE _U_(0x00) /**< \brief (ADC_CTRLA reset_value) Control A */ + +#define ADC_CTRLA_SWRST_Pos 0 /**< \brief (ADC_CTRLA) Software Reset */ +#define ADC_CTRLA_SWRST (_U_(0x1) << ADC_CTRLA_SWRST_Pos) +#define ADC_CTRLA_ENABLE_Pos 1 /**< \brief (ADC_CTRLA) Enable */ +#define ADC_CTRLA_ENABLE (_U_(0x1) << ADC_CTRLA_ENABLE_Pos) +#define ADC_CTRLA_RUNSTDBY_Pos 6 /**< \brief (ADC_CTRLA) Run during Standby */ +#define ADC_CTRLA_RUNSTDBY (_U_(0x1) << ADC_CTRLA_RUNSTDBY_Pos) +#define ADC_CTRLA_ONDEMAND_Pos 7 /**< \brief (ADC_CTRLA) On Demand Control */ +#define ADC_CTRLA_ONDEMAND (_U_(0x1) << ADC_CTRLA_ONDEMAND_Pos) +#define ADC_CTRLA_MASK _U_(0xC3) /**< \brief (ADC_CTRLA) MASK Register */ + +/* -------- ADC_CTRLB : (ADC Offset: 0x01) (R/W 8) Control B -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t PRESCALER:3; /*!< bit: 0.. 2 Prescaler Configuration */ + uint8_t :5; /*!< bit: 3.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + uint8_t reg; /*!< Type used for register access */ +} ADC_CTRLB_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define ADC_CTRLB_OFFSET 0x01 /**< \brief (ADC_CTRLB offset) Control B */ +#define ADC_CTRLB_RESETVALUE _U_(0x00) /**< \brief (ADC_CTRLB reset_value) Control B */ + +#define ADC_CTRLB_PRESCALER_Pos 0 /**< \brief (ADC_CTRLB) Prescaler Configuration */ +#define ADC_CTRLB_PRESCALER_Msk (_U_(0x7) << ADC_CTRLB_PRESCALER_Pos) +#define ADC_CTRLB_PRESCALER(value) (ADC_CTRLB_PRESCALER_Msk & ((value) << ADC_CTRLB_PRESCALER_Pos)) +#define ADC_CTRLB_PRESCALER_DIV2_Val _U_(0x0) /**< \brief (ADC_CTRLB) Peripheral clock divided by 2 */ +#define ADC_CTRLB_PRESCALER_DIV4_Val _U_(0x1) /**< \brief (ADC_CTRLB) Peripheral clock divided by 4 */ +#define ADC_CTRLB_PRESCALER_DIV8_Val _U_(0x2) /**< \brief (ADC_CTRLB) Peripheral clock divided by 8 */ +#define ADC_CTRLB_PRESCALER_DIV16_Val _U_(0x3) /**< \brief (ADC_CTRLB) Peripheral clock divided by 16 */ +#define ADC_CTRLB_PRESCALER_DIV32_Val _U_(0x4) /**< \brief (ADC_CTRLB) Peripheral clock divided by 32 */ +#define ADC_CTRLB_PRESCALER_DIV64_Val _U_(0x5) /**< \brief (ADC_CTRLB) Peripheral clock divided by 64 */ +#define ADC_CTRLB_PRESCALER_DIV128_Val _U_(0x6) /**< \brief (ADC_CTRLB) Peripheral clock divided by 128 */ +#define ADC_CTRLB_PRESCALER_DIV256_Val _U_(0x7) /**< \brief (ADC_CTRLB) Peripheral clock divided by 256 */ +#define ADC_CTRLB_PRESCALER_DIV2 (ADC_CTRLB_PRESCALER_DIV2_Val << ADC_CTRLB_PRESCALER_Pos) +#define ADC_CTRLB_PRESCALER_DIV4 (ADC_CTRLB_PRESCALER_DIV4_Val << ADC_CTRLB_PRESCALER_Pos) +#define ADC_CTRLB_PRESCALER_DIV8 (ADC_CTRLB_PRESCALER_DIV8_Val << ADC_CTRLB_PRESCALER_Pos) +#define ADC_CTRLB_PRESCALER_DIV16 (ADC_CTRLB_PRESCALER_DIV16_Val << ADC_CTRLB_PRESCALER_Pos) +#define ADC_CTRLB_PRESCALER_DIV32 (ADC_CTRLB_PRESCALER_DIV32_Val << ADC_CTRLB_PRESCALER_Pos) +#define ADC_CTRLB_PRESCALER_DIV64 (ADC_CTRLB_PRESCALER_DIV64_Val << ADC_CTRLB_PRESCALER_Pos) +#define ADC_CTRLB_PRESCALER_DIV128 (ADC_CTRLB_PRESCALER_DIV128_Val << ADC_CTRLB_PRESCALER_Pos) +#define ADC_CTRLB_PRESCALER_DIV256 (ADC_CTRLB_PRESCALER_DIV256_Val << ADC_CTRLB_PRESCALER_Pos) +#define ADC_CTRLB_MASK _U_(0x07) /**< \brief (ADC_CTRLB) MASK Register */ + +/* -------- ADC_REFCTRL : (ADC Offset: 0x02) (R/W 8) Reference Control -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t REFSEL:4; /*!< bit: 0.. 3 Reference Selection */ + uint8_t :3; /*!< bit: 4.. 6 Reserved */ + uint8_t REFCOMP:1; /*!< bit: 7 Reference Buffer Offset Compensation Enable */ + } bit; /*!< Structure used for bit access */ + uint8_t reg; /*!< Type used for register access */ +} ADC_REFCTRL_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define ADC_REFCTRL_OFFSET 0x02 /**< \brief (ADC_REFCTRL offset) Reference Control */ +#define ADC_REFCTRL_RESETVALUE _U_(0x00) /**< \brief (ADC_REFCTRL reset_value) Reference Control */ + +#define ADC_REFCTRL_REFSEL_Pos 0 /**< \brief (ADC_REFCTRL) Reference Selection */ +#define ADC_REFCTRL_REFSEL_Msk (_U_(0xF) << ADC_REFCTRL_REFSEL_Pos) +#define ADC_REFCTRL_REFSEL(value) (ADC_REFCTRL_REFSEL_Msk & ((value) << ADC_REFCTRL_REFSEL_Pos)) +#define ADC_REFCTRL_REFSEL_INTREF_Val _U_(0x0) /**< \brief (ADC_REFCTRL) Internal Bandgap Reference */ +#define ADC_REFCTRL_REFSEL_INTVCC0_Val _U_(0x1) /**< \brief (ADC_REFCTRL) 1/1.6 VDDANA */ +#define ADC_REFCTRL_REFSEL_INTVCC1_Val _U_(0x2) /**< \brief (ADC_REFCTRL) 1/2 VDDANA */ +#define ADC_REFCTRL_REFSEL_AREFA_Val _U_(0x3) /**< \brief (ADC_REFCTRL) External Reference */ +#define ADC_REFCTRL_REFSEL_AREFB_Val _U_(0x4) /**< \brief (ADC_REFCTRL) External Reference */ +#define ADC_REFCTRL_REFSEL_INTVCC2_Val _U_(0x5) /**< \brief (ADC_REFCTRL) VCCANA */ +#define ADC_REFCTRL_REFSEL_INTREF (ADC_REFCTRL_REFSEL_INTREF_Val << ADC_REFCTRL_REFSEL_Pos) +#define ADC_REFCTRL_REFSEL_INTVCC0 (ADC_REFCTRL_REFSEL_INTVCC0_Val << ADC_REFCTRL_REFSEL_Pos) +#define ADC_REFCTRL_REFSEL_INTVCC1 (ADC_REFCTRL_REFSEL_INTVCC1_Val << ADC_REFCTRL_REFSEL_Pos) +#define ADC_REFCTRL_REFSEL_AREFA (ADC_REFCTRL_REFSEL_AREFA_Val << ADC_REFCTRL_REFSEL_Pos) +#define ADC_REFCTRL_REFSEL_AREFB (ADC_REFCTRL_REFSEL_AREFB_Val << ADC_REFCTRL_REFSEL_Pos) +#define ADC_REFCTRL_REFSEL_INTVCC2 (ADC_REFCTRL_REFSEL_INTVCC2_Val << ADC_REFCTRL_REFSEL_Pos) +#define ADC_REFCTRL_REFCOMP_Pos 7 /**< \brief (ADC_REFCTRL) Reference Buffer Offset Compensation Enable */ +#define ADC_REFCTRL_REFCOMP (_U_(0x1) << ADC_REFCTRL_REFCOMP_Pos) +#define ADC_REFCTRL_MASK _U_(0x8F) /**< \brief (ADC_REFCTRL) MASK Register */ + +/* -------- ADC_EVCTRL : (ADC Offset: 0x03) (R/W 8) Event Control -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t FLUSHEI:1; /*!< bit: 0 Flush Event Input Enable */ + uint8_t STARTEI:1; /*!< bit: 1 Start Conversion Event Input Enable */ + uint8_t FLUSHINV:1; /*!< bit: 2 Flush Event Invert Enable */ + uint8_t STARTINV:1; /*!< bit: 3 Satrt Event Invert Enable */ + uint8_t RESRDYEO:1; /*!< bit: 4 Result Ready Event Out */ + uint8_t WINMONEO:1; /*!< bit: 5 Window Monitor Event Out */ + uint8_t :2; /*!< bit: 6.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + uint8_t reg; /*!< Type used for register access */ +} ADC_EVCTRL_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define ADC_EVCTRL_OFFSET 0x03 /**< \brief (ADC_EVCTRL offset) Event Control */ +#define ADC_EVCTRL_RESETVALUE _U_(0x00) /**< \brief (ADC_EVCTRL reset_value) Event Control */ + +#define ADC_EVCTRL_FLUSHEI_Pos 0 /**< \brief (ADC_EVCTRL) Flush Event Input Enable */ +#define ADC_EVCTRL_FLUSHEI (_U_(0x1) << ADC_EVCTRL_FLUSHEI_Pos) +#define ADC_EVCTRL_STARTEI_Pos 1 /**< \brief (ADC_EVCTRL) Start Conversion Event Input Enable */ +#define ADC_EVCTRL_STARTEI (_U_(0x1) << ADC_EVCTRL_STARTEI_Pos) +#define ADC_EVCTRL_FLUSHINV_Pos 2 /**< \brief (ADC_EVCTRL) Flush Event Invert Enable */ +#define ADC_EVCTRL_FLUSHINV (_U_(0x1) << ADC_EVCTRL_FLUSHINV_Pos) +#define ADC_EVCTRL_STARTINV_Pos 3 /**< \brief (ADC_EVCTRL) Satrt Event Invert Enable */ +#define ADC_EVCTRL_STARTINV (_U_(0x1) << ADC_EVCTRL_STARTINV_Pos) +#define ADC_EVCTRL_RESRDYEO_Pos 4 /**< \brief (ADC_EVCTRL) Result Ready Event Out */ +#define ADC_EVCTRL_RESRDYEO (_U_(0x1) << ADC_EVCTRL_RESRDYEO_Pos) +#define ADC_EVCTRL_WINMONEO_Pos 5 /**< \brief (ADC_EVCTRL) Window Monitor Event Out */ +#define ADC_EVCTRL_WINMONEO (_U_(0x1) << ADC_EVCTRL_WINMONEO_Pos) +#define ADC_EVCTRL_MASK _U_(0x3F) /**< \brief (ADC_EVCTRL) MASK Register */ + +/* -------- ADC_INTENCLR : (ADC Offset: 0x04) (R/W 8) Interrupt Enable Clear -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t RESRDY:1; /*!< bit: 0 Result Ready Interrupt Disable */ + uint8_t OVERRUN:1; /*!< bit: 1 Overrun Interrupt Disable */ + uint8_t WINMON:1; /*!< bit: 2 Window Monitor Interrupt Disable */ + uint8_t :5; /*!< bit: 3.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + uint8_t reg; /*!< Type used for register access */ +} ADC_INTENCLR_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define ADC_INTENCLR_OFFSET 0x04 /**< \brief (ADC_INTENCLR offset) Interrupt Enable Clear */ +#define ADC_INTENCLR_RESETVALUE _U_(0x00) /**< \brief (ADC_INTENCLR reset_value) Interrupt Enable Clear */ + +#define ADC_INTENCLR_RESRDY_Pos 0 /**< \brief (ADC_INTENCLR) Result Ready Interrupt Disable */ +#define ADC_INTENCLR_RESRDY (_U_(0x1) << ADC_INTENCLR_RESRDY_Pos) +#define ADC_INTENCLR_OVERRUN_Pos 1 /**< \brief (ADC_INTENCLR) Overrun Interrupt Disable */ +#define ADC_INTENCLR_OVERRUN (_U_(0x1) << ADC_INTENCLR_OVERRUN_Pos) +#define ADC_INTENCLR_WINMON_Pos 2 /**< \brief (ADC_INTENCLR) Window Monitor Interrupt Disable */ +#define ADC_INTENCLR_WINMON (_U_(0x1) << ADC_INTENCLR_WINMON_Pos) +#define ADC_INTENCLR_MASK _U_(0x07) /**< \brief (ADC_INTENCLR) MASK Register */ + +/* -------- ADC_INTENSET : (ADC Offset: 0x05) (R/W 8) Interrupt Enable Set -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t RESRDY:1; /*!< bit: 0 Result Ready Interrupt Enable */ + uint8_t OVERRUN:1; /*!< bit: 1 Overrun Interrupt Enable */ + uint8_t WINMON:1; /*!< bit: 2 Window Monitor Interrupt Enable */ + uint8_t :5; /*!< bit: 3.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + uint8_t reg; /*!< Type used for register access */ +} ADC_INTENSET_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define ADC_INTENSET_OFFSET 0x05 /**< \brief (ADC_INTENSET offset) Interrupt Enable Set */ +#define ADC_INTENSET_RESETVALUE _U_(0x00) /**< \brief (ADC_INTENSET reset_value) Interrupt Enable Set */ + +#define ADC_INTENSET_RESRDY_Pos 0 /**< \brief (ADC_INTENSET) Result Ready Interrupt Enable */ +#define ADC_INTENSET_RESRDY (_U_(0x1) << ADC_INTENSET_RESRDY_Pos) +#define ADC_INTENSET_OVERRUN_Pos 1 /**< \brief (ADC_INTENSET) Overrun Interrupt Enable */ +#define ADC_INTENSET_OVERRUN (_U_(0x1) << ADC_INTENSET_OVERRUN_Pos) +#define ADC_INTENSET_WINMON_Pos 2 /**< \brief (ADC_INTENSET) Window Monitor Interrupt Enable */ +#define ADC_INTENSET_WINMON (_U_(0x1) << ADC_INTENSET_WINMON_Pos) +#define ADC_INTENSET_MASK _U_(0x07) /**< \brief (ADC_INTENSET) MASK Register */ + +/* -------- ADC_INTFLAG : (ADC Offset: 0x06) (R/W 8) Interrupt Flag Status and Clear -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { // __I to avoid read-modify-write on write-to-clear register + struct { + __I uint8_t RESRDY:1; /*!< bit: 0 Result Ready Interrupt Flag */ + __I uint8_t OVERRUN:1; /*!< bit: 1 Overrun Interrupt Flag */ + __I uint8_t WINMON:1; /*!< bit: 2 Window Monitor Interrupt Flag */ + __I uint8_t :5; /*!< bit: 3.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + uint8_t reg; /*!< Type used for register access */ +} ADC_INTFLAG_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define ADC_INTFLAG_OFFSET 0x06 /**< \brief (ADC_INTFLAG offset) Interrupt Flag Status and Clear */ +#define ADC_INTFLAG_RESETVALUE _U_(0x00) /**< \brief (ADC_INTFLAG reset_value) Interrupt Flag Status and Clear */ + +#define ADC_INTFLAG_RESRDY_Pos 0 /**< \brief (ADC_INTFLAG) Result Ready Interrupt Flag */ +#define ADC_INTFLAG_RESRDY (_U_(0x1) << ADC_INTFLAG_RESRDY_Pos) +#define ADC_INTFLAG_OVERRUN_Pos 1 /**< \brief (ADC_INTFLAG) Overrun Interrupt Flag */ +#define ADC_INTFLAG_OVERRUN (_U_(0x1) << ADC_INTFLAG_OVERRUN_Pos) +#define ADC_INTFLAG_WINMON_Pos 2 /**< \brief (ADC_INTFLAG) Window Monitor Interrupt Flag */ +#define ADC_INTFLAG_WINMON (_U_(0x1) << ADC_INTFLAG_WINMON_Pos) +#define ADC_INTFLAG_MASK _U_(0x07) /**< \brief (ADC_INTFLAG) MASK Register */ + +/* -------- ADC_SEQSTATUS : (ADC Offset: 0x07) (R/ 8) Sequence Status -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t SEQSTATE:5; /*!< bit: 0.. 4 Sequence State */ + uint8_t :2; /*!< bit: 5.. 6 Reserved */ + uint8_t SEQBUSY:1; /*!< bit: 7 Sequence Busy */ + } bit; /*!< Structure used for bit access */ + uint8_t reg; /*!< Type used for register access */ +} ADC_SEQSTATUS_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define ADC_SEQSTATUS_OFFSET 0x07 /**< \brief (ADC_SEQSTATUS offset) Sequence Status */ +#define ADC_SEQSTATUS_RESETVALUE _U_(0x00) /**< \brief (ADC_SEQSTATUS reset_value) Sequence Status */ + +#define ADC_SEQSTATUS_SEQSTATE_Pos 0 /**< \brief (ADC_SEQSTATUS) Sequence State */ +#define ADC_SEQSTATUS_SEQSTATE_Msk (_U_(0x1F) << ADC_SEQSTATUS_SEQSTATE_Pos) +#define ADC_SEQSTATUS_SEQSTATE(value) (ADC_SEQSTATUS_SEQSTATE_Msk & ((value) << ADC_SEQSTATUS_SEQSTATE_Pos)) +#define ADC_SEQSTATUS_SEQBUSY_Pos 7 /**< \brief (ADC_SEQSTATUS) Sequence Busy */ +#define ADC_SEQSTATUS_SEQBUSY (_U_(0x1) << ADC_SEQSTATUS_SEQBUSY_Pos) +#define ADC_SEQSTATUS_MASK _U_(0x9F) /**< \brief (ADC_SEQSTATUS) MASK Register */ + +/* -------- ADC_INPUTCTRL : (ADC Offset: 0x08) (R/W 16) Input Control -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint16_t MUXPOS:5; /*!< bit: 0.. 4 Positive Mux Input Selection */ + uint16_t :3; /*!< bit: 5.. 7 Reserved */ + uint16_t MUXNEG:5; /*!< bit: 8..12 Negative Mux Input Selection */ + uint16_t :3; /*!< bit: 13..15 Reserved */ + } bit; /*!< Structure used for bit access */ + uint16_t reg; /*!< Type used for register access */ +} ADC_INPUTCTRL_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define ADC_INPUTCTRL_OFFSET 0x08 /**< \brief (ADC_INPUTCTRL offset) Input Control */ +#define ADC_INPUTCTRL_RESETVALUE _U_(0x0000) /**< \brief (ADC_INPUTCTRL reset_value) Input Control */ + +#define ADC_INPUTCTRL_MUXPOS_Pos 0 /**< \brief (ADC_INPUTCTRL) Positive Mux Input Selection */ +#define ADC_INPUTCTRL_MUXPOS_Msk (_U_(0x1F) << ADC_INPUTCTRL_MUXPOS_Pos) +#define ADC_INPUTCTRL_MUXPOS(value) (ADC_INPUTCTRL_MUXPOS_Msk & ((value) << ADC_INPUTCTRL_MUXPOS_Pos)) +#define ADC_INPUTCTRL_MUXPOS_AIN0_Val _U_(0x0) /**< \brief (ADC_INPUTCTRL) ADC AIN0 Pin */ +#define ADC_INPUTCTRL_MUXPOS_AIN1_Val _U_(0x1) /**< \brief (ADC_INPUTCTRL) ADC AIN1 Pin */ +#define ADC_INPUTCTRL_MUXPOS_AIN2_Val _U_(0x2) /**< \brief (ADC_INPUTCTRL) ADC AIN2 Pin */ +#define ADC_INPUTCTRL_MUXPOS_AIN3_Val _U_(0x3) /**< \brief (ADC_INPUTCTRL) ADC AIN3 Pin */ +#define ADC_INPUTCTRL_MUXPOS_AIN4_Val _U_(0x4) /**< \brief (ADC_INPUTCTRL) ADC AIN4 Pin */ +#define ADC_INPUTCTRL_MUXPOS_AIN5_Val _U_(0x5) /**< \brief (ADC_INPUTCTRL) ADC AIN5 Pin */ +#define ADC_INPUTCTRL_MUXPOS_AIN6_Val _U_(0x6) /**< \brief (ADC_INPUTCTRL) ADC AIN6 Pin */ +#define ADC_INPUTCTRL_MUXPOS_AIN7_Val _U_(0x7) /**< \brief (ADC_INPUTCTRL) ADC AIN7 Pin */ +#define ADC_INPUTCTRL_MUXPOS_AIN8_Val _U_(0x8) /**< \brief (ADC_INPUTCTRL) ADC AIN8 Pin */ +#define ADC_INPUTCTRL_MUXPOS_AIN9_Val _U_(0x9) /**< \brief (ADC_INPUTCTRL) ADC AIN9 Pin */ +#define ADC_INPUTCTRL_MUXPOS_AIN10_Val _U_(0xA) /**< \brief (ADC_INPUTCTRL) ADC AIN10 Pin */ +#define ADC_INPUTCTRL_MUXPOS_AIN11_Val _U_(0xB) /**< \brief (ADC_INPUTCTRL) ADC AIN11 Pin */ +#define ADC_INPUTCTRL_MUXPOS_AIN12_Val _U_(0xC) /**< \brief (ADC_INPUTCTRL) ADC AIN12 Pin */ +#define ADC_INPUTCTRL_MUXPOS_AIN13_Val _U_(0xD) /**< \brief (ADC_INPUTCTRL) ADC AIN13 Pin */ +#define ADC_INPUTCTRL_MUXPOS_AIN14_Val _U_(0xE) /**< \brief (ADC_INPUTCTRL) ADC AIN14 Pin */ +#define ADC_INPUTCTRL_MUXPOS_AIN15_Val _U_(0xF) /**< \brief (ADC_INPUTCTRL) ADC AIN15 Pin */ +#define ADC_INPUTCTRL_MUXPOS_AIN16_Val _U_(0x10) /**< \brief (ADC_INPUTCTRL) ADC AIN16 Pin */ +#define ADC_INPUTCTRL_MUXPOS_AIN17_Val _U_(0x11) /**< \brief (ADC_INPUTCTRL) ADC AIN17 Pin */ +#define ADC_INPUTCTRL_MUXPOS_AIN18_Val _U_(0x12) /**< \brief (ADC_INPUTCTRL) ADC AIN18 Pin */ +#define ADC_INPUTCTRL_MUXPOS_AIN19_Val _U_(0x13) /**< \brief (ADC_INPUTCTRL) ADC AIN19 Pin */ +#define ADC_INPUTCTRL_MUXPOS_TEMP_Val _U_(0x18) /**< \brief (ADC_INPUTCTRL) Temperature Sensor */ +#define ADC_INPUTCTRL_MUXPOS_BANDGAP_Val _U_(0x19) /**< \brief (ADC_INPUTCTRL) Bandgap Voltage */ +#define ADC_INPUTCTRL_MUXPOS_SCALEDCOREVCC_Val _U_(0x1A) /**< \brief (ADC_INPUTCTRL) 1/4 Scaled Core Supply */ +#define ADC_INPUTCTRL_MUXPOS_SCALEDIOVCC_Val _U_(0x1B) /**< \brief (ADC_INPUTCTRL) 1/4 Scaled I/O Supply */ +#define ADC_INPUTCTRL_MUXPOS_AIN0 (ADC_INPUTCTRL_MUXPOS_AIN0_Val << ADC_INPUTCTRL_MUXPOS_Pos) +#define ADC_INPUTCTRL_MUXPOS_AIN1 (ADC_INPUTCTRL_MUXPOS_AIN1_Val << ADC_INPUTCTRL_MUXPOS_Pos) +#define ADC_INPUTCTRL_MUXPOS_AIN2 (ADC_INPUTCTRL_MUXPOS_AIN2_Val << ADC_INPUTCTRL_MUXPOS_Pos) +#define ADC_INPUTCTRL_MUXPOS_AIN3 (ADC_INPUTCTRL_MUXPOS_AIN3_Val << ADC_INPUTCTRL_MUXPOS_Pos) +#define ADC_INPUTCTRL_MUXPOS_AIN4 (ADC_INPUTCTRL_MUXPOS_AIN4_Val << ADC_INPUTCTRL_MUXPOS_Pos) +#define ADC_INPUTCTRL_MUXPOS_AIN5 (ADC_INPUTCTRL_MUXPOS_AIN5_Val << ADC_INPUTCTRL_MUXPOS_Pos) +#define ADC_INPUTCTRL_MUXPOS_AIN6 (ADC_INPUTCTRL_MUXPOS_AIN6_Val << ADC_INPUTCTRL_MUXPOS_Pos) +#define ADC_INPUTCTRL_MUXPOS_AIN7 (ADC_INPUTCTRL_MUXPOS_AIN7_Val << ADC_INPUTCTRL_MUXPOS_Pos) +#define ADC_INPUTCTRL_MUXPOS_AIN8 (ADC_INPUTCTRL_MUXPOS_AIN8_Val << ADC_INPUTCTRL_MUXPOS_Pos) +#define ADC_INPUTCTRL_MUXPOS_AIN9 (ADC_INPUTCTRL_MUXPOS_AIN9_Val << ADC_INPUTCTRL_MUXPOS_Pos) +#define ADC_INPUTCTRL_MUXPOS_AIN10 (ADC_INPUTCTRL_MUXPOS_AIN10_Val << ADC_INPUTCTRL_MUXPOS_Pos) +#define ADC_INPUTCTRL_MUXPOS_AIN11 (ADC_INPUTCTRL_MUXPOS_AIN11_Val << ADC_INPUTCTRL_MUXPOS_Pos) +#define ADC_INPUTCTRL_MUXPOS_AIN12 (ADC_INPUTCTRL_MUXPOS_AIN12_Val << ADC_INPUTCTRL_MUXPOS_Pos) +#define ADC_INPUTCTRL_MUXPOS_AIN13 (ADC_INPUTCTRL_MUXPOS_AIN13_Val << ADC_INPUTCTRL_MUXPOS_Pos) +#define ADC_INPUTCTRL_MUXPOS_AIN14 (ADC_INPUTCTRL_MUXPOS_AIN14_Val << ADC_INPUTCTRL_MUXPOS_Pos) +#define ADC_INPUTCTRL_MUXPOS_AIN15 (ADC_INPUTCTRL_MUXPOS_AIN15_Val << ADC_INPUTCTRL_MUXPOS_Pos) +#define ADC_INPUTCTRL_MUXPOS_AIN16 (ADC_INPUTCTRL_MUXPOS_AIN16_Val << ADC_INPUTCTRL_MUXPOS_Pos) +#define ADC_INPUTCTRL_MUXPOS_AIN17 (ADC_INPUTCTRL_MUXPOS_AIN17_Val << ADC_INPUTCTRL_MUXPOS_Pos) +#define ADC_INPUTCTRL_MUXPOS_AIN18 (ADC_INPUTCTRL_MUXPOS_AIN18_Val << ADC_INPUTCTRL_MUXPOS_Pos) +#define ADC_INPUTCTRL_MUXPOS_AIN19 (ADC_INPUTCTRL_MUXPOS_AIN19_Val << ADC_INPUTCTRL_MUXPOS_Pos) +#define ADC_INPUTCTRL_MUXPOS_TEMP (ADC_INPUTCTRL_MUXPOS_TEMP_Val << ADC_INPUTCTRL_MUXPOS_Pos) +#define ADC_INPUTCTRL_MUXPOS_BANDGAP (ADC_INPUTCTRL_MUXPOS_BANDGAP_Val << ADC_INPUTCTRL_MUXPOS_Pos) +#define ADC_INPUTCTRL_MUXPOS_SCALEDCOREVCC (ADC_INPUTCTRL_MUXPOS_SCALEDCOREVCC_Val << ADC_INPUTCTRL_MUXPOS_Pos) +#define ADC_INPUTCTRL_MUXPOS_SCALEDIOVCC (ADC_INPUTCTRL_MUXPOS_SCALEDIOVCC_Val << ADC_INPUTCTRL_MUXPOS_Pos) +#define ADC_INPUTCTRL_MUXNEG_Pos 8 /**< \brief (ADC_INPUTCTRL) Negative Mux Input Selection */ +#define ADC_INPUTCTRL_MUXNEG_Msk (_U_(0x1F) << ADC_INPUTCTRL_MUXNEG_Pos) +#define ADC_INPUTCTRL_MUXNEG(value) (ADC_INPUTCTRL_MUXNEG_Msk & ((value) << ADC_INPUTCTRL_MUXNEG_Pos)) +#define ADC_INPUTCTRL_MUXNEG_AIN0_Val _U_(0x0) /**< \brief (ADC_INPUTCTRL) ADC AIN0 Pin */ +#define ADC_INPUTCTRL_MUXNEG_AIN1_Val _U_(0x1) /**< \brief (ADC_INPUTCTRL) ADC AIN1 Pin */ +#define ADC_INPUTCTRL_MUXNEG_AIN2_Val _U_(0x2) /**< \brief (ADC_INPUTCTRL) ADC AIN2 Pin */ +#define ADC_INPUTCTRL_MUXNEG_AIN3_Val _U_(0x3) /**< \brief (ADC_INPUTCTRL) ADC AIN3 Pin */ +#define ADC_INPUTCTRL_MUXNEG_AIN4_Val _U_(0x4) /**< \brief (ADC_INPUTCTRL) ADC AIN4 Pin */ +#define ADC_INPUTCTRL_MUXNEG_AIN5_Val _U_(0x5) /**< \brief (ADC_INPUTCTRL) ADC AIN5 Pin */ +#define ADC_INPUTCTRL_MUXNEG_GND_Val _U_(0x18) /**< \brief (ADC_INPUTCTRL) Internal ground */ +#define ADC_INPUTCTRL_MUXNEG_AIN0 (ADC_INPUTCTRL_MUXNEG_AIN0_Val << ADC_INPUTCTRL_MUXNEG_Pos) +#define ADC_INPUTCTRL_MUXNEG_AIN1 (ADC_INPUTCTRL_MUXNEG_AIN1_Val << ADC_INPUTCTRL_MUXNEG_Pos) +#define ADC_INPUTCTRL_MUXNEG_AIN2 (ADC_INPUTCTRL_MUXNEG_AIN2_Val << ADC_INPUTCTRL_MUXNEG_Pos) +#define ADC_INPUTCTRL_MUXNEG_AIN3 (ADC_INPUTCTRL_MUXNEG_AIN3_Val << ADC_INPUTCTRL_MUXNEG_Pos) +#define ADC_INPUTCTRL_MUXNEG_AIN4 (ADC_INPUTCTRL_MUXNEG_AIN4_Val << ADC_INPUTCTRL_MUXNEG_Pos) +#define ADC_INPUTCTRL_MUXNEG_AIN5 (ADC_INPUTCTRL_MUXNEG_AIN5_Val << ADC_INPUTCTRL_MUXNEG_Pos) +#define ADC_INPUTCTRL_MUXNEG_GND (ADC_INPUTCTRL_MUXNEG_GND_Val << ADC_INPUTCTRL_MUXNEG_Pos) +#define ADC_INPUTCTRL_MASK _U_(0x1F1F) /**< \brief (ADC_INPUTCTRL) MASK Register */ + +/* -------- ADC_CTRLC : (ADC Offset: 0x0A) (R/W 16) Control C -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint16_t DIFFMODE:1; /*!< bit: 0 Differential Mode */ + uint16_t LEFTADJ:1; /*!< bit: 1 Left-Adjusted Result */ + uint16_t FREERUN:1; /*!< bit: 2 Free Running Mode */ + uint16_t CORREN:1; /*!< bit: 3 Digital Correction Logic Enable */ + uint16_t RESSEL:2; /*!< bit: 4.. 5 Conversion Result Resolution */ + uint16_t :2; /*!< bit: 6.. 7 Reserved */ + uint16_t WINMODE:3; /*!< bit: 8..10 Window Monitor Mode */ + uint16_t :5; /*!< bit: 11..15 Reserved */ + } bit; /*!< Structure used for bit access */ + uint16_t reg; /*!< Type used for register access */ +} ADC_CTRLC_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define ADC_CTRLC_OFFSET 0x0A /**< \brief (ADC_CTRLC offset) Control C */ +#define ADC_CTRLC_RESETVALUE _U_(0x0000) /**< \brief (ADC_CTRLC reset_value) Control C */ + +#define ADC_CTRLC_DIFFMODE_Pos 0 /**< \brief (ADC_CTRLC) Differential Mode */ +#define ADC_CTRLC_DIFFMODE (_U_(0x1) << ADC_CTRLC_DIFFMODE_Pos) +#define ADC_CTRLC_LEFTADJ_Pos 1 /**< \brief (ADC_CTRLC) Left-Adjusted Result */ +#define ADC_CTRLC_LEFTADJ (_U_(0x1) << ADC_CTRLC_LEFTADJ_Pos) +#define ADC_CTRLC_FREERUN_Pos 2 /**< \brief (ADC_CTRLC) Free Running Mode */ +#define ADC_CTRLC_FREERUN (_U_(0x1) << ADC_CTRLC_FREERUN_Pos) +#define ADC_CTRLC_CORREN_Pos 3 /**< \brief (ADC_CTRLC) Digital Correction Logic Enable */ +#define ADC_CTRLC_CORREN (_U_(0x1) << ADC_CTRLC_CORREN_Pos) +#define ADC_CTRLC_RESSEL_Pos 4 /**< \brief (ADC_CTRLC) Conversion Result Resolution */ +#define ADC_CTRLC_RESSEL_Msk (_U_(0x3) << ADC_CTRLC_RESSEL_Pos) +#define ADC_CTRLC_RESSEL(value) (ADC_CTRLC_RESSEL_Msk & ((value) << ADC_CTRLC_RESSEL_Pos)) +#define ADC_CTRLC_RESSEL_12BIT_Val _U_(0x0) /**< \brief (ADC_CTRLC) 12-bit result */ +#define ADC_CTRLC_RESSEL_16BIT_Val _U_(0x1) /**< \brief (ADC_CTRLC) For averaging mode output */ +#define ADC_CTRLC_RESSEL_10BIT_Val _U_(0x2) /**< \brief (ADC_CTRLC) 10-bit result */ +#define ADC_CTRLC_RESSEL_8BIT_Val _U_(0x3) /**< \brief (ADC_CTRLC) 8-bit result */ +#define ADC_CTRLC_RESSEL_12BIT (ADC_CTRLC_RESSEL_12BIT_Val << ADC_CTRLC_RESSEL_Pos) +#define ADC_CTRLC_RESSEL_16BIT (ADC_CTRLC_RESSEL_16BIT_Val << ADC_CTRLC_RESSEL_Pos) +#define ADC_CTRLC_RESSEL_10BIT (ADC_CTRLC_RESSEL_10BIT_Val << ADC_CTRLC_RESSEL_Pos) +#define ADC_CTRLC_RESSEL_8BIT (ADC_CTRLC_RESSEL_8BIT_Val << ADC_CTRLC_RESSEL_Pos) +#define ADC_CTRLC_WINMODE_Pos 8 /**< \brief (ADC_CTRLC) Window Monitor Mode */ +#define ADC_CTRLC_WINMODE_Msk (_U_(0x7) << ADC_CTRLC_WINMODE_Pos) +#define ADC_CTRLC_WINMODE(value) (ADC_CTRLC_WINMODE_Msk & ((value) << ADC_CTRLC_WINMODE_Pos)) +#define ADC_CTRLC_WINMODE_DISABLE_Val _U_(0x0) /**< \brief (ADC_CTRLC) No window mode (default) */ +#define ADC_CTRLC_WINMODE_MODE1_Val _U_(0x1) /**< \brief (ADC_CTRLC) RESULT > WINLT */ +#define ADC_CTRLC_WINMODE_MODE2_Val _U_(0x2) /**< \brief (ADC_CTRLC) RESULT < WINUT */ +#define ADC_CTRLC_WINMODE_MODE3_Val _U_(0x3) /**< \brief (ADC_CTRLC) WINLT < RESULT < WINUT */ +#define ADC_CTRLC_WINMODE_MODE4_Val _U_(0x4) /**< \brief (ADC_CTRLC) !(WINLT < RESULT < WINUT) */ +#define ADC_CTRLC_WINMODE_DISABLE (ADC_CTRLC_WINMODE_DISABLE_Val << ADC_CTRLC_WINMODE_Pos) +#define ADC_CTRLC_WINMODE_MODE1 (ADC_CTRLC_WINMODE_MODE1_Val << ADC_CTRLC_WINMODE_Pos) +#define ADC_CTRLC_WINMODE_MODE2 (ADC_CTRLC_WINMODE_MODE2_Val << ADC_CTRLC_WINMODE_Pos) +#define ADC_CTRLC_WINMODE_MODE3 (ADC_CTRLC_WINMODE_MODE3_Val << ADC_CTRLC_WINMODE_Pos) +#define ADC_CTRLC_WINMODE_MODE4 (ADC_CTRLC_WINMODE_MODE4_Val << ADC_CTRLC_WINMODE_Pos) +#define ADC_CTRLC_MASK _U_(0x073F) /**< \brief (ADC_CTRLC) MASK Register */ + +/* -------- ADC_AVGCTRL : (ADC Offset: 0x0C) (R/W 8) Average Control -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t SAMPLENUM:4; /*!< bit: 0.. 3 Number of Samples to be Collected */ + uint8_t ADJRES:3; /*!< bit: 4.. 6 Adjusting Result / Division Coefficient */ + uint8_t :1; /*!< bit: 7 Reserved */ + } bit; /*!< Structure used for bit access */ + uint8_t reg; /*!< Type used for register access */ +} ADC_AVGCTRL_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define ADC_AVGCTRL_OFFSET 0x0C /**< \brief (ADC_AVGCTRL offset) Average Control */ +#define ADC_AVGCTRL_RESETVALUE _U_(0x00) /**< \brief (ADC_AVGCTRL reset_value) Average Control */ + +#define ADC_AVGCTRL_SAMPLENUM_Pos 0 /**< \brief (ADC_AVGCTRL) Number of Samples to be Collected */ +#define ADC_AVGCTRL_SAMPLENUM_Msk (_U_(0xF) << ADC_AVGCTRL_SAMPLENUM_Pos) +#define ADC_AVGCTRL_SAMPLENUM(value) (ADC_AVGCTRL_SAMPLENUM_Msk & ((value) << ADC_AVGCTRL_SAMPLENUM_Pos)) +#define ADC_AVGCTRL_SAMPLENUM_1_Val _U_(0x0) /**< \brief (ADC_AVGCTRL) 1 sample */ +#define ADC_AVGCTRL_SAMPLENUM_2_Val _U_(0x1) /**< \brief (ADC_AVGCTRL) 2 samples */ +#define ADC_AVGCTRL_SAMPLENUM_4_Val _U_(0x2) /**< \brief (ADC_AVGCTRL) 4 samples */ +#define ADC_AVGCTRL_SAMPLENUM_8_Val _U_(0x3) /**< \brief (ADC_AVGCTRL) 8 samples */ +#define ADC_AVGCTRL_SAMPLENUM_16_Val _U_(0x4) /**< \brief (ADC_AVGCTRL) 16 samples */ +#define ADC_AVGCTRL_SAMPLENUM_32_Val _U_(0x5) /**< \brief (ADC_AVGCTRL) 32 samples */ +#define ADC_AVGCTRL_SAMPLENUM_64_Val _U_(0x6) /**< \brief (ADC_AVGCTRL) 64 samples */ +#define ADC_AVGCTRL_SAMPLENUM_128_Val _U_(0x7) /**< \brief (ADC_AVGCTRL) 128 samples */ +#define ADC_AVGCTRL_SAMPLENUM_256_Val _U_(0x8) /**< \brief (ADC_AVGCTRL) 256 samples */ +#define ADC_AVGCTRL_SAMPLENUM_512_Val _U_(0x9) /**< \brief (ADC_AVGCTRL) 512 samples */ +#define ADC_AVGCTRL_SAMPLENUM_1024_Val _U_(0xA) /**< \brief (ADC_AVGCTRL) 1024 samples */ +#define ADC_AVGCTRL_SAMPLENUM_1 (ADC_AVGCTRL_SAMPLENUM_1_Val << ADC_AVGCTRL_SAMPLENUM_Pos) +#define ADC_AVGCTRL_SAMPLENUM_2 (ADC_AVGCTRL_SAMPLENUM_2_Val << ADC_AVGCTRL_SAMPLENUM_Pos) +#define ADC_AVGCTRL_SAMPLENUM_4 (ADC_AVGCTRL_SAMPLENUM_4_Val << ADC_AVGCTRL_SAMPLENUM_Pos) +#define ADC_AVGCTRL_SAMPLENUM_8 (ADC_AVGCTRL_SAMPLENUM_8_Val << ADC_AVGCTRL_SAMPLENUM_Pos) +#define ADC_AVGCTRL_SAMPLENUM_16 (ADC_AVGCTRL_SAMPLENUM_16_Val << ADC_AVGCTRL_SAMPLENUM_Pos) +#define ADC_AVGCTRL_SAMPLENUM_32 (ADC_AVGCTRL_SAMPLENUM_32_Val << ADC_AVGCTRL_SAMPLENUM_Pos) +#define ADC_AVGCTRL_SAMPLENUM_64 (ADC_AVGCTRL_SAMPLENUM_64_Val << ADC_AVGCTRL_SAMPLENUM_Pos) +#define ADC_AVGCTRL_SAMPLENUM_128 (ADC_AVGCTRL_SAMPLENUM_128_Val << ADC_AVGCTRL_SAMPLENUM_Pos) +#define ADC_AVGCTRL_SAMPLENUM_256 (ADC_AVGCTRL_SAMPLENUM_256_Val << ADC_AVGCTRL_SAMPLENUM_Pos) +#define ADC_AVGCTRL_SAMPLENUM_512 (ADC_AVGCTRL_SAMPLENUM_512_Val << ADC_AVGCTRL_SAMPLENUM_Pos) +#define ADC_AVGCTRL_SAMPLENUM_1024 (ADC_AVGCTRL_SAMPLENUM_1024_Val << ADC_AVGCTRL_SAMPLENUM_Pos) +#define ADC_AVGCTRL_ADJRES_Pos 4 /**< \brief (ADC_AVGCTRL) Adjusting Result / Division Coefficient */ +#define ADC_AVGCTRL_ADJRES_Msk (_U_(0x7) << ADC_AVGCTRL_ADJRES_Pos) +#define ADC_AVGCTRL_ADJRES(value) (ADC_AVGCTRL_ADJRES_Msk & ((value) << ADC_AVGCTRL_ADJRES_Pos)) +#define ADC_AVGCTRL_MASK _U_(0x7F) /**< \brief (ADC_AVGCTRL) MASK Register */ + +/* -------- ADC_SAMPCTRL : (ADC Offset: 0x0D) (R/W 8) Sample Time Control -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t SAMPLEN:6; /*!< bit: 0.. 5 Sampling Time Length */ + uint8_t :1; /*!< bit: 6 Reserved */ + uint8_t OFFCOMP:1; /*!< bit: 7 Comparator Offset Compensation Enable */ + } bit; /*!< Structure used for bit access */ + uint8_t reg; /*!< Type used for register access */ +} ADC_SAMPCTRL_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define ADC_SAMPCTRL_OFFSET 0x0D /**< \brief (ADC_SAMPCTRL offset) Sample Time Control */ +#define ADC_SAMPCTRL_RESETVALUE _U_(0x00) /**< \brief (ADC_SAMPCTRL reset_value) Sample Time Control */ + +#define ADC_SAMPCTRL_SAMPLEN_Pos 0 /**< \brief (ADC_SAMPCTRL) Sampling Time Length */ +#define ADC_SAMPCTRL_SAMPLEN_Msk (_U_(0x3F) << ADC_SAMPCTRL_SAMPLEN_Pos) +#define ADC_SAMPCTRL_SAMPLEN(value) (ADC_SAMPCTRL_SAMPLEN_Msk & ((value) << ADC_SAMPCTRL_SAMPLEN_Pos)) +#define ADC_SAMPCTRL_OFFCOMP_Pos 7 /**< \brief (ADC_SAMPCTRL) Comparator Offset Compensation Enable */ +#define ADC_SAMPCTRL_OFFCOMP (_U_(0x1) << ADC_SAMPCTRL_OFFCOMP_Pos) +#define ADC_SAMPCTRL_MASK _U_(0xBF) /**< \brief (ADC_SAMPCTRL) MASK Register */ + +/* -------- ADC_WINLT : (ADC Offset: 0x0E) (R/W 16) Window Monitor Lower Threshold -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint16_t WINLT:16; /*!< bit: 0..15 Window Lower Threshold */ + } bit; /*!< Structure used for bit access */ + uint16_t reg; /*!< Type used for register access */ +} ADC_WINLT_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define ADC_WINLT_OFFSET 0x0E /**< \brief (ADC_WINLT offset) Window Monitor Lower Threshold */ +#define ADC_WINLT_RESETVALUE _U_(0x0000) /**< \brief (ADC_WINLT reset_value) Window Monitor Lower Threshold */ + +#define ADC_WINLT_WINLT_Pos 0 /**< \brief (ADC_WINLT) Window Lower Threshold */ +#define ADC_WINLT_WINLT_Msk (_U_(0xFFFF) << ADC_WINLT_WINLT_Pos) +#define ADC_WINLT_WINLT(value) (ADC_WINLT_WINLT_Msk & ((value) << ADC_WINLT_WINLT_Pos)) +#define ADC_WINLT_MASK _U_(0xFFFF) /**< \brief (ADC_WINLT) MASK Register */ + +/* -------- ADC_WINUT : (ADC Offset: 0x10) (R/W 16) Window Monitor Upper Threshold -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint16_t WINUT:16; /*!< bit: 0..15 Window Upper Threshold */ + } bit; /*!< Structure used for bit access */ + uint16_t reg; /*!< Type used for register access */ +} ADC_WINUT_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define ADC_WINUT_OFFSET 0x10 /**< \brief (ADC_WINUT offset) Window Monitor Upper Threshold */ +#define ADC_WINUT_RESETVALUE _U_(0x0000) /**< \brief (ADC_WINUT reset_value) Window Monitor Upper Threshold */ + +#define ADC_WINUT_WINUT_Pos 0 /**< \brief (ADC_WINUT) Window Upper Threshold */ +#define ADC_WINUT_WINUT_Msk (_U_(0xFFFF) << ADC_WINUT_WINUT_Pos) +#define ADC_WINUT_WINUT(value) (ADC_WINUT_WINUT_Msk & ((value) << ADC_WINUT_WINUT_Pos)) +#define ADC_WINUT_MASK _U_(0xFFFF) /**< \brief (ADC_WINUT) MASK Register */ + +/* -------- ADC_GAINCORR : (ADC Offset: 0x12) (R/W 16) Gain Correction -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint16_t GAINCORR:12; /*!< bit: 0..11 Gain Correction Value */ + uint16_t :4; /*!< bit: 12..15 Reserved */ + } bit; /*!< Structure used for bit access */ + uint16_t reg; /*!< Type used for register access */ +} ADC_GAINCORR_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define ADC_GAINCORR_OFFSET 0x12 /**< \brief (ADC_GAINCORR offset) Gain Correction */ +#define ADC_GAINCORR_RESETVALUE _U_(0x0000) /**< \brief (ADC_GAINCORR reset_value) Gain Correction */ + +#define ADC_GAINCORR_GAINCORR_Pos 0 /**< \brief (ADC_GAINCORR) Gain Correction Value */ +#define ADC_GAINCORR_GAINCORR_Msk (_U_(0xFFF) << ADC_GAINCORR_GAINCORR_Pos) +#define ADC_GAINCORR_GAINCORR(value) (ADC_GAINCORR_GAINCORR_Msk & ((value) << ADC_GAINCORR_GAINCORR_Pos)) +#define ADC_GAINCORR_MASK _U_(0x0FFF) /**< \brief (ADC_GAINCORR) MASK Register */ + +/* -------- ADC_OFFSETCORR : (ADC Offset: 0x14) (R/W 16) Offset Correction -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint16_t OFFSETCORR:12; /*!< bit: 0..11 Offset Correction Value */ + uint16_t :4; /*!< bit: 12..15 Reserved */ + } bit; /*!< Structure used for bit access */ + uint16_t reg; /*!< Type used for register access */ +} ADC_OFFSETCORR_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define ADC_OFFSETCORR_OFFSET 0x14 /**< \brief (ADC_OFFSETCORR offset) Offset Correction */ +#define ADC_OFFSETCORR_RESETVALUE _U_(0x0000) /**< \brief (ADC_OFFSETCORR reset_value) Offset Correction */ + +#define ADC_OFFSETCORR_OFFSETCORR_Pos 0 /**< \brief (ADC_OFFSETCORR) Offset Correction Value */ +#define ADC_OFFSETCORR_OFFSETCORR_Msk (_U_(0xFFF) << ADC_OFFSETCORR_OFFSETCORR_Pos) +#define ADC_OFFSETCORR_OFFSETCORR(value) (ADC_OFFSETCORR_OFFSETCORR_Msk & ((value) << ADC_OFFSETCORR_OFFSETCORR_Pos)) +#define ADC_OFFSETCORR_MASK _U_(0x0FFF) /**< \brief (ADC_OFFSETCORR) MASK Register */ + +/* -------- ADC_SWTRIG : (ADC Offset: 0x18) (R/W 8) Software Trigger -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t FLUSH:1; /*!< bit: 0 ADC Flush */ + uint8_t START:1; /*!< bit: 1 Start ADC Conversion */ + uint8_t :6; /*!< bit: 2.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + uint8_t reg; /*!< Type used for register access */ +} ADC_SWTRIG_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define ADC_SWTRIG_OFFSET 0x18 /**< \brief (ADC_SWTRIG offset) Software Trigger */ +#define ADC_SWTRIG_RESETVALUE _U_(0x00) /**< \brief (ADC_SWTRIG reset_value) Software Trigger */ + +#define ADC_SWTRIG_FLUSH_Pos 0 /**< \brief (ADC_SWTRIG) ADC Flush */ +#define ADC_SWTRIG_FLUSH (_U_(0x1) << ADC_SWTRIG_FLUSH_Pos) +#define ADC_SWTRIG_START_Pos 1 /**< \brief (ADC_SWTRIG) Start ADC Conversion */ +#define ADC_SWTRIG_START (_U_(0x1) << ADC_SWTRIG_START_Pos) +#define ADC_SWTRIG_MASK _U_(0x03) /**< \brief (ADC_SWTRIG) MASK Register */ + +/* -------- ADC_DBGCTRL : (ADC Offset: 0x1C) (R/W 8) Debug Control -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t DBGRUN:1; /*!< bit: 0 Debug Run */ + uint8_t :7; /*!< bit: 1.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + uint8_t reg; /*!< Type used for register access */ +} ADC_DBGCTRL_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define ADC_DBGCTRL_OFFSET 0x1C /**< \brief (ADC_DBGCTRL offset) Debug Control */ +#define ADC_DBGCTRL_RESETVALUE _U_(0x00) /**< \brief (ADC_DBGCTRL reset_value) Debug Control */ + +#define ADC_DBGCTRL_DBGRUN_Pos 0 /**< \brief (ADC_DBGCTRL) Debug Run */ +#define ADC_DBGCTRL_DBGRUN (_U_(0x1) << ADC_DBGCTRL_DBGRUN_Pos) +#define ADC_DBGCTRL_MASK _U_(0x01) /**< \brief (ADC_DBGCTRL) MASK Register */ + +/* -------- ADC_SYNCBUSY : (ADC Offset: 0x20) (R/ 16) Synchronization Busy -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint16_t SWRST:1; /*!< bit: 0 SWRST Synchronization Busy */ + uint16_t ENABLE:1; /*!< bit: 1 ENABLE Synchronization Busy */ + uint16_t INPUTCTRL:1; /*!< bit: 2 INPUTCTRL Synchronization Busy */ + uint16_t CTRLC:1; /*!< bit: 3 CTRLC Synchronization Busy */ + uint16_t AVGCTRL:1; /*!< bit: 4 AVGCTRL Synchronization Busy */ + uint16_t SAMPCTRL:1; /*!< bit: 5 SAMPCTRL Synchronization Busy */ + uint16_t WINLT:1; /*!< bit: 6 WINLT Synchronization Busy */ + uint16_t WINUT:1; /*!< bit: 7 WINUT Synchronization Busy */ + uint16_t GAINCORR:1; /*!< bit: 8 GAINCORR Synchronization Busy */ + uint16_t OFFSETCORR:1; /*!< bit: 9 OFFSETCTRL Synchronization Busy */ + uint16_t SWTRIG:1; /*!< bit: 10 SWTRG Synchronization Busy */ + uint16_t :5; /*!< bit: 11..15 Reserved */ + } bit; /*!< Structure used for bit access */ + uint16_t reg; /*!< Type used for register access */ +} ADC_SYNCBUSY_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define ADC_SYNCBUSY_OFFSET 0x20 /**< \brief (ADC_SYNCBUSY offset) Synchronization Busy */ +#define ADC_SYNCBUSY_RESETVALUE _U_(0x0000) /**< \brief (ADC_SYNCBUSY reset_value) Synchronization Busy */ + +#define ADC_SYNCBUSY_SWRST_Pos 0 /**< \brief (ADC_SYNCBUSY) SWRST Synchronization Busy */ +#define ADC_SYNCBUSY_SWRST (_U_(0x1) << ADC_SYNCBUSY_SWRST_Pos) +#define ADC_SYNCBUSY_ENABLE_Pos 1 /**< \brief (ADC_SYNCBUSY) ENABLE Synchronization Busy */ +#define ADC_SYNCBUSY_ENABLE (_U_(0x1) << ADC_SYNCBUSY_ENABLE_Pos) +#define ADC_SYNCBUSY_INPUTCTRL_Pos 2 /**< \brief (ADC_SYNCBUSY) INPUTCTRL Synchronization Busy */ +#define ADC_SYNCBUSY_INPUTCTRL (_U_(0x1) << ADC_SYNCBUSY_INPUTCTRL_Pos) +#define ADC_SYNCBUSY_CTRLC_Pos 3 /**< \brief (ADC_SYNCBUSY) CTRLC Synchronization Busy */ +#define ADC_SYNCBUSY_CTRLC (_U_(0x1) << ADC_SYNCBUSY_CTRLC_Pos) +#define ADC_SYNCBUSY_AVGCTRL_Pos 4 /**< \brief (ADC_SYNCBUSY) AVGCTRL Synchronization Busy */ +#define ADC_SYNCBUSY_AVGCTRL (_U_(0x1) << ADC_SYNCBUSY_AVGCTRL_Pos) +#define ADC_SYNCBUSY_SAMPCTRL_Pos 5 /**< \brief (ADC_SYNCBUSY) SAMPCTRL Synchronization Busy */ +#define ADC_SYNCBUSY_SAMPCTRL (_U_(0x1) << ADC_SYNCBUSY_SAMPCTRL_Pos) +#define ADC_SYNCBUSY_WINLT_Pos 6 /**< \brief (ADC_SYNCBUSY) WINLT Synchronization Busy */ +#define ADC_SYNCBUSY_WINLT (_U_(0x1) << ADC_SYNCBUSY_WINLT_Pos) +#define ADC_SYNCBUSY_WINUT_Pos 7 /**< \brief (ADC_SYNCBUSY) WINUT Synchronization Busy */ +#define ADC_SYNCBUSY_WINUT (_U_(0x1) << ADC_SYNCBUSY_WINUT_Pos) +#define ADC_SYNCBUSY_GAINCORR_Pos 8 /**< \brief (ADC_SYNCBUSY) GAINCORR Synchronization Busy */ +#define ADC_SYNCBUSY_GAINCORR (_U_(0x1) << ADC_SYNCBUSY_GAINCORR_Pos) +#define ADC_SYNCBUSY_OFFSETCORR_Pos 9 /**< \brief (ADC_SYNCBUSY) OFFSETCTRL Synchronization Busy */ +#define ADC_SYNCBUSY_OFFSETCORR (_U_(0x1) << ADC_SYNCBUSY_OFFSETCORR_Pos) +#define ADC_SYNCBUSY_SWTRIG_Pos 10 /**< \brief (ADC_SYNCBUSY) SWTRG Synchronization Busy */ +#define ADC_SYNCBUSY_SWTRIG (_U_(0x1) << ADC_SYNCBUSY_SWTRIG_Pos) +#define ADC_SYNCBUSY_MASK _U_(0x07FF) /**< \brief (ADC_SYNCBUSY) MASK Register */ + +/* -------- ADC_RESULT : (ADC Offset: 0x24) (R/ 16) Result -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint16_t RESULT:16; /*!< bit: 0..15 Result Value */ + } bit; /*!< Structure used for bit access */ + uint16_t reg; /*!< Type used for register access */ +} ADC_RESULT_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define ADC_RESULT_OFFSET 0x24 /**< \brief (ADC_RESULT offset) Result */ +#define ADC_RESULT_RESETVALUE _U_(0x0000) /**< \brief (ADC_RESULT reset_value) Result */ + +#define ADC_RESULT_RESULT_Pos 0 /**< \brief (ADC_RESULT) Result Value */ +#define ADC_RESULT_RESULT_Msk (_U_(0xFFFF) << ADC_RESULT_RESULT_Pos) +#define ADC_RESULT_RESULT(value) (ADC_RESULT_RESULT_Msk & ((value) << ADC_RESULT_RESULT_Pos)) +#define ADC_RESULT_MASK _U_(0xFFFF) /**< \brief (ADC_RESULT) MASK Register */ + +/* -------- ADC_SEQCTRL : (ADC Offset: 0x28) (R/W 32) Sequence Control -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint32_t SEQEN:32; /*!< bit: 0..31 Enable Positive Input in the Sequence */ + } bit; /*!< Structure used for bit access */ + uint32_t reg; /*!< Type used for register access */ +} ADC_SEQCTRL_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define ADC_SEQCTRL_OFFSET 0x28 /**< \brief (ADC_SEQCTRL offset) Sequence Control */ +#define ADC_SEQCTRL_RESETVALUE _U_(0x00000000) /**< \brief (ADC_SEQCTRL reset_value) Sequence Control */ + +#define ADC_SEQCTRL_SEQEN_Pos 0 /**< \brief (ADC_SEQCTRL) Enable Positive Input in the Sequence */ +#define ADC_SEQCTRL_SEQEN_Msk (_U_(0xFFFFFFFF) << ADC_SEQCTRL_SEQEN_Pos) +#define ADC_SEQCTRL_SEQEN(value) (ADC_SEQCTRL_SEQEN_Msk & ((value) << ADC_SEQCTRL_SEQEN_Pos)) +#define ADC_SEQCTRL_MASK _U_(0xFFFFFFFF) /**< \brief (ADC_SEQCTRL) MASK Register */ + +/* -------- ADC_CALIB : (ADC Offset: 0x2C) (R/W 16) Calibration -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint16_t BIASCOMP:3; /*!< bit: 0.. 2 Bias Comparator Scaling */ + uint16_t :5; /*!< bit: 3.. 7 Reserved */ + uint16_t BIASREFBUF:3; /*!< bit: 8..10 Bias Reference Buffer Scaling */ + uint16_t :5; /*!< bit: 11..15 Reserved */ + } bit; /*!< Structure used for bit access */ + uint16_t reg; /*!< Type used for register access */ +} ADC_CALIB_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define ADC_CALIB_OFFSET 0x2C /**< \brief (ADC_CALIB offset) Calibration */ +#define ADC_CALIB_RESETVALUE _U_(0x0000) /**< \brief (ADC_CALIB reset_value) Calibration */ + +#define ADC_CALIB_BIASCOMP_Pos 0 /**< \brief (ADC_CALIB) Bias Comparator Scaling */ +#define ADC_CALIB_BIASCOMP_Msk (_U_(0x7) << ADC_CALIB_BIASCOMP_Pos) +#define ADC_CALIB_BIASCOMP(value) (ADC_CALIB_BIASCOMP_Msk & ((value) << ADC_CALIB_BIASCOMP_Pos)) +#define ADC_CALIB_BIASREFBUF_Pos 8 /**< \brief (ADC_CALIB) Bias Reference Buffer Scaling */ +#define ADC_CALIB_BIASREFBUF_Msk (_U_(0x7) << ADC_CALIB_BIASREFBUF_Pos) +#define ADC_CALIB_BIASREFBUF(value) (ADC_CALIB_BIASREFBUF_Msk & ((value) << ADC_CALIB_BIASREFBUF_Pos)) +#define ADC_CALIB_MASK _U_(0x0707) /**< \brief (ADC_CALIB) MASK Register */ + +/** \brief ADC hardware registers */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef struct { + __IO ADC_CTRLA_Type CTRLA; /**< \brief Offset: 0x00 (R/W 8) Control A */ + __IO ADC_CTRLB_Type CTRLB; /**< \brief Offset: 0x01 (R/W 8) Control B */ + __IO ADC_REFCTRL_Type REFCTRL; /**< \brief Offset: 0x02 (R/W 8) Reference Control */ + __IO ADC_EVCTRL_Type EVCTRL; /**< \brief Offset: 0x03 (R/W 8) Event Control */ + __IO ADC_INTENCLR_Type INTENCLR; /**< \brief Offset: 0x04 (R/W 8) Interrupt Enable Clear */ + __IO ADC_INTENSET_Type INTENSET; /**< \brief Offset: 0x05 (R/W 8) Interrupt Enable Set */ + __IO ADC_INTFLAG_Type INTFLAG; /**< \brief Offset: 0x06 (R/W 8) Interrupt Flag Status and Clear */ + __I ADC_SEQSTATUS_Type SEQSTATUS; /**< \brief Offset: 0x07 (R/ 8) Sequence Status */ + __IO ADC_INPUTCTRL_Type INPUTCTRL; /**< \brief Offset: 0x08 (R/W 16) Input Control */ + __IO ADC_CTRLC_Type CTRLC; /**< \brief Offset: 0x0A (R/W 16) Control C */ + __IO ADC_AVGCTRL_Type AVGCTRL; /**< \brief Offset: 0x0C (R/W 8) Average Control */ + __IO ADC_SAMPCTRL_Type SAMPCTRL; /**< \brief Offset: 0x0D (R/W 8) Sample Time Control */ + __IO ADC_WINLT_Type WINLT; /**< \brief Offset: 0x0E (R/W 16) Window Monitor Lower Threshold */ + __IO ADC_WINUT_Type WINUT; /**< \brief Offset: 0x10 (R/W 16) Window Monitor Upper Threshold */ + __IO ADC_GAINCORR_Type GAINCORR; /**< \brief Offset: 0x12 (R/W 16) Gain Correction */ + __IO ADC_OFFSETCORR_Type OFFSETCORR; /**< \brief Offset: 0x14 (R/W 16) Offset Correction */ + RoReg8 Reserved1[0x2]; + __IO ADC_SWTRIG_Type SWTRIG; /**< \brief Offset: 0x18 (R/W 8) Software Trigger */ + RoReg8 Reserved2[0x3]; + __IO ADC_DBGCTRL_Type DBGCTRL; /**< \brief Offset: 0x1C (R/W 8) Debug Control */ + RoReg8 Reserved3[0x3]; + __I ADC_SYNCBUSY_Type SYNCBUSY; /**< \brief Offset: 0x20 (R/ 16) Synchronization Busy */ + RoReg8 Reserved4[0x2]; + __I ADC_RESULT_Type RESULT; /**< \brief Offset: 0x24 (R/ 16) Result */ + RoReg8 Reserved5[0x2]; + __IO ADC_SEQCTRL_Type SEQCTRL; /**< \brief Offset: 0x28 (R/W 32) Sequence Control */ + __IO ADC_CALIB_Type CALIB; /**< \brief Offset: 0x2C (R/W 16) Calibration */ +} Adc; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +/*@}*/ + +#endif /* _SAMR34_ADC_COMPONENT_ */ diff --git a/src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/aes.h b/src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/aes.h new file mode 100644 index 000000000..fd7a238f0 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/aes.h @@ -0,0 +1,325 @@ +/** + * \file + * + * \brief Component description for AES + * + * Copyright (c) 2017 Microchip Technology Inc. + * + * \asf_license_start + * + * \page License + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the Licence at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * \asf_license_stop + * + */ + +#ifndef _SAMR34_AES_COMPONENT_ +#define _SAMR34_AES_COMPONENT_ + +/* ========================================================================== */ +/** SOFTWARE API DEFINITION FOR AES */ +/* ========================================================================== */ +/** \addtogroup SAMR34_AES Advanced Encryption Standard */ +/*@{*/ + +#define AES_U2238 +#define REV_AES 0x200 + +/* -------- AES_CTRLA : (AES Offset: 0x00) (R/W 32) Control A -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint32_t SWRST:1; /*!< bit: 0 Software Reset */ + uint32_t ENABLE:1; /*!< bit: 1 Enable */ + uint32_t AESMODE:3; /*!< bit: 2.. 4 AES Modes of operation */ + uint32_t CFBS:3; /*!< bit: 5.. 7 CFB Types */ + uint32_t KEYSIZE:2; /*!< bit: 8.. 9 Keysize */ + uint32_t CIPHER:1; /*!< bit: 10 Cipher mode */ + uint32_t STARTMODE:1; /*!< bit: 11 Start mode */ + uint32_t LOD:1; /*!< bit: 12 LOD Enable */ + uint32_t KEYGEN:1; /*!< bit: 13 Last key generation */ + uint32_t XORKEY:1; /*!< bit: 14 Xor Key operation */ + uint32_t :1; /*!< bit: 15 Reserved */ + uint32_t CTYPE:4; /*!< bit: 16..19 Counter measure types */ + uint32_t :12; /*!< bit: 20..31 Reserved */ + } bit; /*!< Structure used for bit access */ + uint32_t reg; /*!< Type used for register access */ +} AES_CTRLA_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define AES_CTRLA_OFFSET 0x00 /**< \brief (AES_CTRLA offset) Control A */ +#define AES_CTRLA_RESETVALUE _U_(0x00000000) /**< \brief (AES_CTRLA reset_value) Control A */ + +#define AES_CTRLA_SWRST_Pos 0 /**< \brief (AES_CTRLA) Software Reset */ +#define AES_CTRLA_SWRST (_U_(0x1) << AES_CTRLA_SWRST_Pos) +#define AES_CTRLA_ENABLE_Pos 1 /**< \brief (AES_CTRLA) Enable */ +#define AES_CTRLA_ENABLE (_U_(0x1) << AES_CTRLA_ENABLE_Pos) +#define AES_CTRLA_AESMODE_Pos 2 /**< \brief (AES_CTRLA) AES Modes of operation */ +#define AES_CTRLA_AESMODE_Msk (_U_(0x7) << AES_CTRLA_AESMODE_Pos) +#define AES_CTRLA_AESMODE(value) (AES_CTRLA_AESMODE_Msk & ((value) << AES_CTRLA_AESMODE_Pos)) +#define AES_CTRLA_CFBS_Pos 5 /**< \brief (AES_CTRLA) CFB Types */ +#define AES_CTRLA_CFBS_Msk (_U_(0x7) << AES_CTRLA_CFBS_Pos) +#define AES_CTRLA_CFBS(value) (AES_CTRLA_CFBS_Msk & ((value) << AES_CTRLA_CFBS_Pos)) +#define AES_CTRLA_KEYSIZE_Pos 8 /**< \brief (AES_CTRLA) Keysize */ +#define AES_CTRLA_KEYSIZE_Msk (_U_(0x3) << AES_CTRLA_KEYSIZE_Pos) +#define AES_CTRLA_KEYSIZE(value) (AES_CTRLA_KEYSIZE_Msk & ((value) << AES_CTRLA_KEYSIZE_Pos)) +#define AES_CTRLA_CIPHER_Pos 10 /**< \brief (AES_CTRLA) Cipher mode */ +#define AES_CTRLA_CIPHER (_U_(0x1) << AES_CTRLA_CIPHER_Pos) +#define AES_CTRLA_STARTMODE_Pos 11 /**< \brief (AES_CTRLA) Start mode */ +#define AES_CTRLA_STARTMODE (_U_(0x1) << AES_CTRLA_STARTMODE_Pos) +#define AES_CTRLA_LOD_Pos 12 /**< \brief (AES_CTRLA) LOD Enable */ +#define AES_CTRLA_LOD (_U_(0x1) << AES_CTRLA_LOD_Pos) +#define AES_CTRLA_KEYGEN_Pos 13 /**< \brief (AES_CTRLA) Last key generation */ +#define AES_CTRLA_KEYGEN (_U_(0x1) << AES_CTRLA_KEYGEN_Pos) +#define AES_CTRLA_XORKEY_Pos 14 /**< \brief (AES_CTRLA) Xor Key operation */ +#define AES_CTRLA_XORKEY (_U_(0x1) << AES_CTRLA_XORKEY_Pos) +#define AES_CTRLA_CTYPE_Pos 16 /**< \brief (AES_CTRLA) Counter measure types */ +#define AES_CTRLA_CTYPE_Msk (_U_(0xF) << AES_CTRLA_CTYPE_Pos) +#define AES_CTRLA_CTYPE(value) (AES_CTRLA_CTYPE_Msk & ((value) << AES_CTRLA_CTYPE_Pos)) +#define AES_CTRLA_MASK _U_(0x000F7FFF) /**< \brief (AES_CTRLA) MASK Register */ + +/* -------- AES_CTRLB : (AES Offset: 0x04) (R/W 8) Control B -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t START:1; /*!< bit: 0 Manual Start */ + uint8_t NEWMSG:1; /*!< bit: 1 New message */ + uint8_t EOM:1; /*!< bit: 2 End of message */ + uint8_t GFMUL:1; /*!< bit: 3 GF Multiplication */ + uint8_t :4; /*!< bit: 4.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + uint8_t reg; /*!< Type used for register access */ +} AES_CTRLB_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define AES_CTRLB_OFFSET 0x04 /**< \brief (AES_CTRLB offset) Control B */ +#define AES_CTRLB_RESETVALUE _U_(0x00) /**< \brief (AES_CTRLB reset_value) Control B */ + +#define AES_CTRLB_START_Pos 0 /**< \brief (AES_CTRLB) Manual Start */ +#define AES_CTRLB_START (_U_(0x1) << AES_CTRLB_START_Pos) +#define AES_CTRLB_NEWMSG_Pos 1 /**< \brief (AES_CTRLB) New message */ +#define AES_CTRLB_NEWMSG (_U_(0x1) << AES_CTRLB_NEWMSG_Pos) +#define AES_CTRLB_EOM_Pos 2 /**< \brief (AES_CTRLB) End of message */ +#define AES_CTRLB_EOM (_U_(0x1) << AES_CTRLB_EOM_Pos) +#define AES_CTRLB_GFMUL_Pos 3 /**< \brief (AES_CTRLB) GF Multiplication */ +#define AES_CTRLB_GFMUL (_U_(0x1) << AES_CTRLB_GFMUL_Pos) +#define AES_CTRLB_MASK _U_(0x0F) /**< \brief (AES_CTRLB) MASK Register */ + +/* -------- AES_INTENCLR : (AES Offset: 0x05) (R/W 8) Interrupt Enable Clear -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t ENCCMP:1; /*!< bit: 0 Encryption Complete */ + uint8_t GFMCMP:1; /*!< bit: 1 GF Multiplication Complete */ + uint8_t :6; /*!< bit: 2.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + uint8_t reg; /*!< Type used for register access */ +} AES_INTENCLR_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define AES_INTENCLR_OFFSET 0x05 /**< \brief (AES_INTENCLR offset) Interrupt Enable Clear */ +#define AES_INTENCLR_RESETVALUE _U_(0x00) /**< \brief (AES_INTENCLR reset_value) Interrupt Enable Clear */ + +#define AES_INTENCLR_ENCCMP_Pos 0 /**< \brief (AES_INTENCLR) Encryption Complete */ +#define AES_INTENCLR_ENCCMP (_U_(0x1) << AES_INTENCLR_ENCCMP_Pos) +#define AES_INTENCLR_GFMCMP_Pos 1 /**< \brief (AES_INTENCLR) GF Multiplication Complete */ +#define AES_INTENCLR_GFMCMP (_U_(0x1) << AES_INTENCLR_GFMCMP_Pos) +#define AES_INTENCLR_MASK _U_(0x03) /**< \brief (AES_INTENCLR) MASK Register */ + +/* -------- AES_INTENSET : (AES Offset: 0x06) (R/W 8) Interrupt Enable Set -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t ENCCMP:1; /*!< bit: 0 Encryption Complete */ + uint8_t GFMCMP:1; /*!< bit: 1 GF Multiplication Complete */ + uint8_t :6; /*!< bit: 2.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + uint8_t reg; /*!< Type used for register access */ +} AES_INTENSET_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define AES_INTENSET_OFFSET 0x06 /**< \brief (AES_INTENSET offset) Interrupt Enable Set */ +#define AES_INTENSET_RESETVALUE _U_(0x00) /**< \brief (AES_INTENSET reset_value) Interrupt Enable Set */ + +#define AES_INTENSET_ENCCMP_Pos 0 /**< \brief (AES_INTENSET) Encryption Complete */ +#define AES_INTENSET_ENCCMP (_U_(0x1) << AES_INTENSET_ENCCMP_Pos) +#define AES_INTENSET_GFMCMP_Pos 1 /**< \brief (AES_INTENSET) GF Multiplication Complete */ +#define AES_INTENSET_GFMCMP (_U_(0x1) << AES_INTENSET_GFMCMP_Pos) +#define AES_INTENSET_MASK _U_(0x03) /**< \brief (AES_INTENSET) MASK Register */ + +/* -------- AES_INTFLAG : (AES Offset: 0x07) (R/W 8) Interrupt Flag Status -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { // __I to avoid read-modify-write on write-to-clear register + struct { + __I uint8_t ENCCMP:1; /*!< bit: 0 Encryption Complete */ + __I uint8_t GFMCMP:1; /*!< bit: 1 GF Multiplication Complete */ + __I uint8_t :6; /*!< bit: 2.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + uint8_t reg; /*!< Type used for register access */ +} AES_INTFLAG_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define AES_INTFLAG_OFFSET 0x07 /**< \brief (AES_INTFLAG offset) Interrupt Flag Status */ +#define AES_INTFLAG_RESETVALUE _U_(0x00) /**< \brief (AES_INTFLAG reset_value) Interrupt Flag Status */ + +#define AES_INTFLAG_ENCCMP_Pos 0 /**< \brief (AES_INTFLAG) Encryption Complete */ +#define AES_INTFLAG_ENCCMP (_U_(0x1) << AES_INTFLAG_ENCCMP_Pos) +#define AES_INTFLAG_GFMCMP_Pos 1 /**< \brief (AES_INTFLAG) GF Multiplication Complete */ +#define AES_INTFLAG_GFMCMP (_U_(0x1) << AES_INTFLAG_GFMCMP_Pos) +#define AES_INTFLAG_MASK _U_(0x03) /**< \brief (AES_INTFLAG) MASK Register */ + +/* -------- AES_DATABUFPTR : (AES Offset: 0x08) (R/W 8) Data buffer pointer -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t INDATAPTR:2; /*!< bit: 0.. 1 Input Data Pointer */ + uint8_t :6; /*!< bit: 2.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + uint8_t reg; /*!< Type used for register access */ +} AES_DATABUFPTR_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define AES_DATABUFPTR_OFFSET 0x08 /**< \brief (AES_DATABUFPTR offset) Data buffer pointer */ +#define AES_DATABUFPTR_RESETVALUE _U_(0x00) /**< \brief (AES_DATABUFPTR reset_value) Data buffer pointer */ + +#define AES_DATABUFPTR_INDATAPTR_Pos 0 /**< \brief (AES_DATABUFPTR) Input Data Pointer */ +#define AES_DATABUFPTR_INDATAPTR_Msk (_U_(0x3) << AES_DATABUFPTR_INDATAPTR_Pos) +#define AES_DATABUFPTR_INDATAPTR(value) (AES_DATABUFPTR_INDATAPTR_Msk & ((value) << AES_DATABUFPTR_INDATAPTR_Pos)) +#define AES_DATABUFPTR_MASK _U_(0x03) /**< \brief (AES_DATABUFPTR) MASK Register */ + +/* -------- AES_DBGCTRL : (AES Offset: 0x09) ( /W 8) Debug control -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t DBGRUN:1; /*!< bit: 0 Debug Run */ + uint8_t :7; /*!< bit: 1.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + uint8_t reg; /*!< Type used for register access */ +} AES_DBGCTRL_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define AES_DBGCTRL_OFFSET 0x09 /**< \brief (AES_DBGCTRL offset) Debug control */ +#define AES_DBGCTRL_RESETVALUE _U_(0x00) /**< \brief (AES_DBGCTRL reset_value) Debug control */ + +#define AES_DBGCTRL_DBGRUN_Pos 0 /**< \brief (AES_DBGCTRL) Debug Run */ +#define AES_DBGCTRL_DBGRUN (_U_(0x1) << AES_DBGCTRL_DBGRUN_Pos) +#define AES_DBGCTRL_MASK _U_(0x01) /**< \brief (AES_DBGCTRL) MASK Register */ + +/* -------- AES_KEYWORD : (AES Offset: 0x0C) ( /W 32) Keyword n -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + uint32_t reg; /*!< Type used for register access */ +} AES_KEYWORD_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define AES_KEYWORD_OFFSET 0x0C /**< \brief (AES_KEYWORD offset) Keyword n */ +#define AES_KEYWORD_RESETVALUE _U_(0x00000000) /**< \brief (AES_KEYWORD reset_value) Keyword n */ +#define AES_KEYWORD_MASK _U_(0xFFFFFFFF) /**< \brief (AES_KEYWORD) MASK Register */ + +/* -------- AES_INDATA : (AES Offset: 0x38) (R/W 32) Indata -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + uint32_t reg; /*!< Type used for register access */ +} AES_INDATA_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define AES_INDATA_OFFSET 0x38 /**< \brief (AES_INDATA offset) Indata */ +#define AES_INDATA_RESETVALUE _U_(0x00000000) /**< \brief (AES_INDATA reset_value) Indata */ +#define AES_INDATA_MASK _U_(0xFFFFFFFF) /**< \brief (AES_INDATA) MASK Register */ + +/* -------- AES_INTVECTV : (AES Offset: 0x3C) ( /W 32) Initialisation Vector n -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + uint32_t reg; /*!< Type used for register access */ +} AES_INTVECTV_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define AES_INTVECTV_OFFSET 0x3C /**< \brief (AES_INTVECTV offset) Initialisation Vector n */ +#define AES_INTVECTV_RESETVALUE _U_(0x00000000) /**< \brief (AES_INTVECTV reset_value) Initialisation Vector n */ +#define AES_INTVECTV_MASK _U_(0xFFFFFFFF) /**< \brief (AES_INTVECTV) MASK Register */ + +/* -------- AES_HASHKEY : (AES Offset: 0x5C) (R/W 32) Hash key n -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + uint32_t reg; /*!< Type used for register access */ +} AES_HASHKEY_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define AES_HASHKEY_OFFSET 0x5C /**< \brief (AES_HASHKEY offset) Hash key n */ +#define AES_HASHKEY_RESETVALUE _U_(0x00000000) /**< \brief (AES_HASHKEY reset_value) Hash key n */ +#define AES_HASHKEY_MASK _U_(0xFFFFFFFF) /**< \brief (AES_HASHKEY) MASK Register */ + +/* -------- AES_GHASH : (AES Offset: 0x6C) (R/W 32) Galois Hash n -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + uint32_t reg; /*!< Type used for register access */ +} AES_GHASH_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define AES_GHASH_OFFSET 0x6C /**< \brief (AES_GHASH offset) Galois Hash n */ +#define AES_GHASH_RESETVALUE _U_(0x00000000) /**< \brief (AES_GHASH reset_value) Galois Hash n */ +#define AES_GHASH_MASK _U_(0xFFFFFFFF) /**< \brief (AES_GHASH) MASK Register */ + +/* -------- AES_CIPLEN : (AES Offset: 0x80) (R/W 32) Cipher Length -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + uint32_t reg; /*!< Type used for register access */ +} AES_CIPLEN_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define AES_CIPLEN_OFFSET 0x80 /**< \brief (AES_CIPLEN offset) Cipher Length */ +#define AES_CIPLEN_RESETVALUE _U_(0x00000000) /**< \brief (AES_CIPLEN reset_value) Cipher Length */ +#define AES_CIPLEN_MASK _U_(0xFFFFFFFF) /**< \brief (AES_CIPLEN) MASK Register */ + +/* -------- AES_RANDSEED : (AES Offset: 0x84) (R/W 32) Random Seed -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + uint32_t reg; /*!< Type used for register access */ +} AES_RANDSEED_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define AES_RANDSEED_OFFSET 0x84 /**< \brief (AES_RANDSEED offset) Random Seed */ +#define AES_RANDSEED_RESETVALUE _U_(0x00000000) /**< \brief (AES_RANDSEED reset_value) Random Seed */ +#define AES_RANDSEED_MASK _U_(0xFFFFFFFF) /**< \brief (AES_RANDSEED) MASK Register */ + +/** \brief AES hardware registers */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef struct { + __IO AES_CTRLA_Type CTRLA; /**< \brief Offset: 0x00 (R/W 32) Control A */ + __IO AES_CTRLB_Type CTRLB; /**< \brief Offset: 0x04 (R/W 8) Control B */ + __IO AES_INTENCLR_Type INTENCLR; /**< \brief Offset: 0x05 (R/W 8) Interrupt Enable Clear */ + __IO AES_INTENSET_Type INTENSET; /**< \brief Offset: 0x06 (R/W 8) Interrupt Enable Set */ + __IO AES_INTFLAG_Type INTFLAG; /**< \brief Offset: 0x07 (R/W 8) Interrupt Flag Status */ + __IO AES_DATABUFPTR_Type DATABUFPTR; /**< \brief Offset: 0x08 (R/W 8) Data buffer pointer */ + __O AES_DBGCTRL_Type DBGCTRL; /**< \brief Offset: 0x09 ( /W 8) Debug control */ + RoReg8 Reserved1[0x2]; + __O AES_KEYWORD_Type KEYWORD[8]; /**< \brief Offset: 0x0C ( /W 32) Keyword n */ + RoReg8 Reserved2[0xC]; + __IO AES_INDATA_Type INDATA; /**< \brief Offset: 0x38 (R/W 32) Indata */ + __O AES_INTVECTV_Type INTVECTV[4]; /**< \brief Offset: 0x3C ( /W 32) Initialisation Vector n */ + RoReg8 Reserved3[0x10]; + __IO AES_HASHKEY_Type HASHKEY[4]; /**< \brief Offset: 0x5C (R/W 32) Hash key n */ + __IO AES_GHASH_Type GHASH[4]; /**< \brief Offset: 0x6C (R/W 32) Galois Hash n */ + RoReg8 Reserved4[0x4]; + __IO AES_CIPLEN_Type CIPLEN; /**< \brief Offset: 0x80 (R/W 32) Cipher Length */ + __IO AES_RANDSEED_Type RANDSEED; /**< \brief Offset: 0x84 (R/W 32) Random Seed */ +} Aes; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +/*@}*/ + +#endif /* _SAMR34_AES_COMPONENT_ */ diff --git a/src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/ccl.h b/src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/ccl.h new file mode 100644 index 000000000..684a94fdb --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/ccl.h @@ -0,0 +1,188 @@ +/** + * \file + * + * \brief Component description for CCL + * + * Copyright (c) 2017 Microchip Technology Inc. + * + * \asf_license_start + * + * \page License + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the Licence at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * \asf_license_stop + * + */ + +#ifndef _SAMR34_CCL_COMPONENT_ +#define _SAMR34_CCL_COMPONENT_ + +/* ========================================================================== */ +/** SOFTWARE API DEFINITION FOR CCL */ +/* ========================================================================== */ +/** \addtogroup SAMR34_CCL Configurable Custom Logic */ +/*@{*/ + +#define CCL_U2225 +#define REV_CCL 0x101 + +/* -------- CCL_CTRL : (CCL Offset: 0x0) (R/W 8) Control -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t SWRST:1; /*!< bit: 0 Software Reset */ + uint8_t ENABLE:1; /*!< bit: 1 Enable */ + uint8_t :4; /*!< bit: 2.. 5 Reserved */ + uint8_t RUNSTDBY:1; /*!< bit: 6 Run during Standby */ + uint8_t :1; /*!< bit: 7 Reserved */ + } bit; /*!< Structure used for bit access */ + uint8_t reg; /*!< Type used for register access */ +} CCL_CTRL_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define CCL_CTRL_OFFSET 0x0 /**< \brief (CCL_CTRL offset) Control */ +#define CCL_CTRL_RESETVALUE _U_(0x00) /**< \brief (CCL_CTRL reset_value) Control */ + +#define CCL_CTRL_SWRST_Pos 0 /**< \brief (CCL_CTRL) Software Reset */ +#define CCL_CTRL_SWRST (_U_(0x1) << CCL_CTRL_SWRST_Pos) +#define CCL_CTRL_ENABLE_Pos 1 /**< \brief (CCL_CTRL) Enable */ +#define CCL_CTRL_ENABLE (_U_(0x1) << CCL_CTRL_ENABLE_Pos) +#define CCL_CTRL_RUNSTDBY_Pos 6 /**< \brief (CCL_CTRL) Run during Standby */ +#define CCL_CTRL_RUNSTDBY (_U_(0x1) << CCL_CTRL_RUNSTDBY_Pos) +#define CCL_CTRL_MASK _U_(0x43) /**< \brief (CCL_CTRL) MASK Register */ + +/* -------- CCL_SEQCTRL : (CCL Offset: 0x4) (R/W 8) SEQ Control x -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t SEQSEL:4; /*!< bit: 0.. 3 Sequential Selection */ + uint8_t :4; /*!< bit: 4.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + uint8_t reg; /*!< Type used for register access */ +} CCL_SEQCTRL_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define CCL_SEQCTRL_OFFSET 0x4 /**< \brief (CCL_SEQCTRL offset) SEQ Control x */ +#define CCL_SEQCTRL_RESETVALUE _U_(0x00) /**< \brief (CCL_SEQCTRL reset_value) SEQ Control x */ + +#define CCL_SEQCTRL_SEQSEL_Pos 0 /**< \brief (CCL_SEQCTRL) Sequential Selection */ +#define CCL_SEQCTRL_SEQSEL_Msk (_U_(0xF) << CCL_SEQCTRL_SEQSEL_Pos) +#define CCL_SEQCTRL_SEQSEL(value) (CCL_SEQCTRL_SEQSEL_Msk & ((value) << CCL_SEQCTRL_SEQSEL_Pos)) +#define CCL_SEQCTRL_SEQSEL_DISABLE_Val _U_(0x0) /**< \brief (CCL_SEQCTRL) Sequential logic is disabled */ +#define CCL_SEQCTRL_SEQSEL_DFF_Val _U_(0x1) /**< \brief (CCL_SEQCTRL) D flip flop */ +#define CCL_SEQCTRL_SEQSEL_JK_Val _U_(0x2) /**< \brief (CCL_SEQCTRL) JK flip flop */ +#define CCL_SEQCTRL_SEQSEL_LATCH_Val _U_(0x3) /**< \brief (CCL_SEQCTRL) D latch */ +#define CCL_SEQCTRL_SEQSEL_RS_Val _U_(0x4) /**< \brief (CCL_SEQCTRL) RS latch */ +#define CCL_SEQCTRL_SEQSEL_DISABLE (CCL_SEQCTRL_SEQSEL_DISABLE_Val << CCL_SEQCTRL_SEQSEL_Pos) +#define CCL_SEQCTRL_SEQSEL_DFF (CCL_SEQCTRL_SEQSEL_DFF_Val << CCL_SEQCTRL_SEQSEL_Pos) +#define CCL_SEQCTRL_SEQSEL_JK (CCL_SEQCTRL_SEQSEL_JK_Val << CCL_SEQCTRL_SEQSEL_Pos) +#define CCL_SEQCTRL_SEQSEL_LATCH (CCL_SEQCTRL_SEQSEL_LATCH_Val << CCL_SEQCTRL_SEQSEL_Pos) +#define CCL_SEQCTRL_SEQSEL_RS (CCL_SEQCTRL_SEQSEL_RS_Val << CCL_SEQCTRL_SEQSEL_Pos) +#define CCL_SEQCTRL_MASK _U_(0x0F) /**< \brief (CCL_SEQCTRL) MASK Register */ + +/* -------- CCL_LUTCTRL : (CCL Offset: 0x8) (R/W 32) LUT Control x -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint32_t :1; /*!< bit: 0 Reserved */ + uint32_t ENABLE:1; /*!< bit: 1 LUT Enable */ + uint32_t :2; /*!< bit: 2.. 3 Reserved */ + uint32_t FILTSEL:2; /*!< bit: 4.. 5 Filter Selection */ + uint32_t :1; /*!< bit: 6 Reserved */ + uint32_t EDGESEL:1; /*!< bit: 7 Edge Selection */ + uint32_t INSEL0:4; /*!< bit: 8..11 Input Selection 0 */ + uint32_t INSEL1:4; /*!< bit: 12..15 Input Selection 1 */ + uint32_t INSEL2:4; /*!< bit: 16..19 Input Selection 2 */ + uint32_t INVEI:1; /*!< bit: 20 Input Event Invert */ + uint32_t LUTEI:1; /*!< bit: 21 Event Input Enable */ + uint32_t LUTEO:1; /*!< bit: 22 Event Output Enable */ + uint32_t :1; /*!< bit: 23 Reserved */ + uint32_t TRUTH:8; /*!< bit: 24..31 Truth Value */ + } bit; /*!< Structure used for bit access */ + uint32_t reg; /*!< Type used for register access */ +} CCL_LUTCTRL_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define CCL_LUTCTRL_OFFSET 0x8 /**< \brief (CCL_LUTCTRL offset) LUT Control x */ +#define CCL_LUTCTRL_RESETVALUE _U_(0x00000000) /**< \brief (CCL_LUTCTRL reset_value) LUT Control x */ + +#define CCL_LUTCTRL_ENABLE_Pos 1 /**< \brief (CCL_LUTCTRL) LUT Enable */ +#define CCL_LUTCTRL_ENABLE (_U_(0x1) << CCL_LUTCTRL_ENABLE_Pos) +#define CCL_LUTCTRL_FILTSEL_Pos 4 /**< \brief (CCL_LUTCTRL) Filter Selection */ +#define CCL_LUTCTRL_FILTSEL_Msk (_U_(0x3) << CCL_LUTCTRL_FILTSEL_Pos) +#define CCL_LUTCTRL_FILTSEL(value) (CCL_LUTCTRL_FILTSEL_Msk & ((value) << CCL_LUTCTRL_FILTSEL_Pos)) +#define CCL_LUTCTRL_FILTSEL_DISABLE_Val _U_(0x0) /**< \brief (CCL_LUTCTRL) Filter disabled */ +#define CCL_LUTCTRL_FILTSEL_SYNCH_Val _U_(0x1) /**< \brief (CCL_LUTCTRL) Synchronizer enabled */ +#define CCL_LUTCTRL_FILTSEL_FILTER_Val _U_(0x2) /**< \brief (CCL_LUTCTRL) Filter enabled */ +#define CCL_LUTCTRL_FILTSEL_DISABLE (CCL_LUTCTRL_FILTSEL_DISABLE_Val << CCL_LUTCTRL_FILTSEL_Pos) +#define CCL_LUTCTRL_FILTSEL_SYNCH (CCL_LUTCTRL_FILTSEL_SYNCH_Val << CCL_LUTCTRL_FILTSEL_Pos) +#define CCL_LUTCTRL_FILTSEL_FILTER (CCL_LUTCTRL_FILTSEL_FILTER_Val << CCL_LUTCTRL_FILTSEL_Pos) +#define CCL_LUTCTRL_EDGESEL_Pos 7 /**< \brief (CCL_LUTCTRL) Edge Selection */ +#define CCL_LUTCTRL_EDGESEL (_U_(0x1) << CCL_LUTCTRL_EDGESEL_Pos) +#define CCL_LUTCTRL_INSEL0_Pos 8 /**< \brief (CCL_LUTCTRL) Input Selection 0 */ +#define CCL_LUTCTRL_INSEL0_Msk (_U_(0xF) << CCL_LUTCTRL_INSEL0_Pos) +#define CCL_LUTCTRL_INSEL0(value) (CCL_LUTCTRL_INSEL0_Msk & ((value) << CCL_LUTCTRL_INSEL0_Pos)) +#define CCL_LUTCTRL_INSEL0_MASK_Val _U_(0x0) /**< \brief (CCL_LUTCTRL) Masked input */ +#define CCL_LUTCTRL_INSEL0_FEEDBACK_Val _U_(0x1) /**< \brief (CCL_LUTCTRL) Feedback input source */ +#define CCL_LUTCTRL_INSEL0_LINK_Val _U_(0x2) /**< \brief (CCL_LUTCTRL) Linked LUT input source */ +#define CCL_LUTCTRL_INSEL0_EVENT_Val _U_(0x3) /**< \brief (CCL_LUTCTRL) Event in put source */ +#define CCL_LUTCTRL_INSEL0_IO_Val _U_(0x4) /**< \brief (CCL_LUTCTRL) I/O pin input source */ +#define CCL_LUTCTRL_INSEL0_AC_Val _U_(0x5) /**< \brief (CCL_LUTCTRL) AC input source */ +#define CCL_LUTCTRL_INSEL0_TC_Val _U_(0x6) /**< \brief (CCL_LUTCTRL) TC input source */ +#define CCL_LUTCTRL_INSEL0_ALTTC_Val _U_(0x7) /**< \brief (CCL_LUTCTRL) Alternate TC input source */ +#define CCL_LUTCTRL_INSEL0_TCC_Val _U_(0x8) /**< \brief (CCL_LUTCTRL) TCC input source */ +#define CCL_LUTCTRL_INSEL0_SERCOM_Val _U_(0x9) /**< \brief (CCL_LUTCTRL) SERCOM inout source */ +#define CCL_LUTCTRL_INSEL0_MASK (CCL_LUTCTRL_INSEL0_MASK_Val << CCL_LUTCTRL_INSEL0_Pos) +#define CCL_LUTCTRL_INSEL0_FEEDBACK (CCL_LUTCTRL_INSEL0_FEEDBACK_Val << CCL_LUTCTRL_INSEL0_Pos) +#define CCL_LUTCTRL_INSEL0_LINK (CCL_LUTCTRL_INSEL0_LINK_Val << CCL_LUTCTRL_INSEL0_Pos) +#define CCL_LUTCTRL_INSEL0_EVENT (CCL_LUTCTRL_INSEL0_EVENT_Val << CCL_LUTCTRL_INSEL0_Pos) +#define CCL_LUTCTRL_INSEL0_IO (CCL_LUTCTRL_INSEL0_IO_Val << CCL_LUTCTRL_INSEL0_Pos) +#define CCL_LUTCTRL_INSEL0_AC (CCL_LUTCTRL_INSEL0_AC_Val << CCL_LUTCTRL_INSEL0_Pos) +#define CCL_LUTCTRL_INSEL0_TC (CCL_LUTCTRL_INSEL0_TC_Val << CCL_LUTCTRL_INSEL0_Pos) +#define CCL_LUTCTRL_INSEL0_ALTTC (CCL_LUTCTRL_INSEL0_ALTTC_Val << CCL_LUTCTRL_INSEL0_Pos) +#define CCL_LUTCTRL_INSEL0_TCC (CCL_LUTCTRL_INSEL0_TCC_Val << CCL_LUTCTRL_INSEL0_Pos) +#define CCL_LUTCTRL_INSEL0_SERCOM (CCL_LUTCTRL_INSEL0_SERCOM_Val << CCL_LUTCTRL_INSEL0_Pos) +#define CCL_LUTCTRL_INSEL1_Pos 12 /**< \brief (CCL_LUTCTRL) Input Selection 1 */ +#define CCL_LUTCTRL_INSEL1_Msk (_U_(0xF) << CCL_LUTCTRL_INSEL1_Pos) +#define CCL_LUTCTRL_INSEL1(value) (CCL_LUTCTRL_INSEL1_Msk & ((value) << CCL_LUTCTRL_INSEL1_Pos)) +#define CCL_LUTCTRL_INSEL2_Pos 16 /**< \brief (CCL_LUTCTRL) Input Selection 2 */ +#define CCL_LUTCTRL_INSEL2_Msk (_U_(0xF) << CCL_LUTCTRL_INSEL2_Pos) +#define CCL_LUTCTRL_INSEL2(value) (CCL_LUTCTRL_INSEL2_Msk & ((value) << CCL_LUTCTRL_INSEL2_Pos)) +#define CCL_LUTCTRL_INVEI_Pos 20 /**< \brief (CCL_LUTCTRL) Input Event Invert */ +#define CCL_LUTCTRL_INVEI (_U_(0x1) << CCL_LUTCTRL_INVEI_Pos) +#define CCL_LUTCTRL_LUTEI_Pos 21 /**< \brief (CCL_LUTCTRL) Event Input Enable */ +#define CCL_LUTCTRL_LUTEI (_U_(0x1) << CCL_LUTCTRL_LUTEI_Pos) +#define CCL_LUTCTRL_LUTEO_Pos 22 /**< \brief (CCL_LUTCTRL) Event Output Enable */ +#define CCL_LUTCTRL_LUTEO (_U_(0x1) << CCL_LUTCTRL_LUTEO_Pos) +#define CCL_LUTCTRL_TRUTH_Pos 24 /**< \brief (CCL_LUTCTRL) Truth Value */ +#define CCL_LUTCTRL_TRUTH_Msk (_U_(0xFF) << CCL_LUTCTRL_TRUTH_Pos) +#define CCL_LUTCTRL_TRUTH(value) (CCL_LUTCTRL_TRUTH_Msk & ((value) << CCL_LUTCTRL_TRUTH_Pos)) +#define CCL_LUTCTRL_MASK _U_(0xFF7FFFB2) /**< \brief (CCL_LUTCTRL) MASK Register */ + +/** \brief CCL hardware registers */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef struct { + __IO CCL_CTRL_Type CTRL; /**< \brief Offset: 0x0 (R/W 8) Control */ + RoReg8 Reserved1[0x3]; + __IO CCL_SEQCTRL_Type SEQCTRL[2]; /**< \brief Offset: 0x4 (R/W 8) SEQ Control x */ + RoReg8 Reserved2[0x2]; + __IO CCL_LUTCTRL_Type LUTCTRL[4]; /**< \brief Offset: 0x8 (R/W 32) LUT Control x */ +} Ccl; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +/*@}*/ + +#endif /* _SAMR34_CCL_COMPONENT_ */ diff --git a/src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/dac.h b/src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/dac.h new file mode 100644 index 000000000..2e69cfc1b --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/dac.h @@ -0,0 +1,455 @@ +/** + * \file + * + * \brief Component description for DAC + * + * Copyright (c) 2017 Microchip Technology Inc. + * + * \asf_license_start + * + * \page License + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the Licence at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * \asf_license_stop + * + */ + +#ifndef _SAMR34_DAC_COMPONENT_ +#define _SAMR34_DAC_COMPONENT_ + +/* ========================================================================== */ +/** SOFTWARE API DEFINITION FOR DAC */ +/* ========================================================================== */ +/** \addtogroup SAMR34_DAC Digital-to-Analog Converter */ +/*@{*/ + +#define DAC_U2244 +#define REV_DAC 0x112 + +/* -------- DAC_CTRLA : (DAC Offset: 0x00) (R/W 8) Control A -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t SWRST:1; /*!< bit: 0 Software Reset */ + uint8_t ENABLE:1; /*!< bit: 1 Enable DAC Controller */ + uint8_t :6; /*!< bit: 2.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + uint8_t reg; /*!< Type used for register access */ +} DAC_CTRLA_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define DAC_CTRLA_OFFSET 0x00 /**< \brief (DAC_CTRLA offset) Control A */ +#define DAC_CTRLA_RESETVALUE _U_(0x00) /**< \brief (DAC_CTRLA reset_value) Control A */ + +#define DAC_CTRLA_SWRST_Pos 0 /**< \brief (DAC_CTRLA) Software Reset */ +#define DAC_CTRLA_SWRST (_U_(0x1) << DAC_CTRLA_SWRST_Pos) +#define DAC_CTRLA_ENABLE_Pos 1 /**< \brief (DAC_CTRLA) Enable DAC Controller */ +#define DAC_CTRLA_ENABLE (_U_(0x1) << DAC_CTRLA_ENABLE_Pos) +#define DAC_CTRLA_MASK _U_(0x03) /**< \brief (DAC_CTRLA) MASK Register */ + +/* -------- DAC_CTRLB : (DAC Offset: 0x01) (R/W 8) Control B -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t DIFF:1; /*!< bit: 0 Differential mode enable */ + uint8_t REFSEL:2; /*!< bit: 1.. 2 Reference Selection for DAC0/1 */ + uint8_t :5; /*!< bit: 3.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + uint8_t reg; /*!< Type used for register access */ +} DAC_CTRLB_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define DAC_CTRLB_OFFSET 0x01 /**< \brief (DAC_CTRLB offset) Control B */ +#define DAC_CTRLB_RESETVALUE _U_(0x00) /**< \brief (DAC_CTRLB reset_value) Control B */ + +#define DAC_CTRLB_DIFF_Pos 0 /**< \brief (DAC_CTRLB) Differential mode enable */ +#define DAC_CTRLB_DIFF (_U_(0x1) << DAC_CTRLB_DIFF_Pos) +#define DAC_CTRLB_REFSEL_Pos 1 /**< \brief (DAC_CTRLB) Reference Selection for DAC0/1 */ +#define DAC_CTRLB_REFSEL_Msk (_U_(0x3) << DAC_CTRLB_REFSEL_Pos) +#define DAC_CTRLB_REFSEL(value) (DAC_CTRLB_REFSEL_Msk & ((value) << DAC_CTRLB_REFSEL_Pos)) +#define DAC_CTRLB_REFSEL_VREFPU_Val _U_(0x0) /**< \brief (DAC_CTRLB) External reference unbuffered */ +#define DAC_CTRLB_REFSEL_VDDANA_Val _U_(0x1) /**< \brief (DAC_CTRLB) Analog supply */ +#define DAC_CTRLB_REFSEL_VREFPB_Val _U_(0x2) /**< \brief (DAC_CTRLB) External reference buffered */ +#define DAC_CTRLB_REFSEL_INTREF_Val _U_(0x3) /**< \brief (DAC_CTRLB) Internal bandgap reference */ +#define DAC_CTRLB_REFSEL_VREFPU (DAC_CTRLB_REFSEL_VREFPU_Val << DAC_CTRLB_REFSEL_Pos) +#define DAC_CTRLB_REFSEL_VDDANA (DAC_CTRLB_REFSEL_VDDANA_Val << DAC_CTRLB_REFSEL_Pos) +#define DAC_CTRLB_REFSEL_VREFPB (DAC_CTRLB_REFSEL_VREFPB_Val << DAC_CTRLB_REFSEL_Pos) +#define DAC_CTRLB_REFSEL_INTREF (DAC_CTRLB_REFSEL_INTREF_Val << DAC_CTRLB_REFSEL_Pos) +#define DAC_CTRLB_MASK _U_(0x07) /**< \brief (DAC_CTRLB) MASK Register */ + +/* -------- DAC_EVCTRL : (DAC Offset: 0x02) (R/W 8) Event Control -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t STARTEI0:1; /*!< bit: 0 Start Conversion Event Input DAC 0 */ + uint8_t STARTEI1:1; /*!< bit: 1 Start Conversion Event Input DAC 1 */ + uint8_t EMPTYEO0:1; /*!< bit: 2 Data Buffer Empty Event Output DAC 0 */ + uint8_t EMPTYEO1:1; /*!< bit: 3 Data Buffer Empty Event Output DAC 1 */ + uint8_t INVEI0:1; /*!< bit: 4 Enable Invertion of DAC 0 input event */ + uint8_t INVEI1:1; /*!< bit: 5 Enable Invertion of DAC 1 input event */ + uint8_t :2; /*!< bit: 6.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + struct { + uint8_t STARTEI:2; /*!< bit: 0.. 1 Start Conversion Event Input DAC x */ + uint8_t EMPTYEO:2; /*!< bit: 2.. 3 Data Buffer Empty Event Output DAC x */ + uint8_t INVEI:2; /*!< bit: 4.. 5 Enable Invertion of DAC x input event */ + uint8_t :2; /*!< bit: 6.. 7 Reserved */ + } vec; /*!< Structure used for vec access */ + uint8_t reg; /*!< Type used for register access */ +} DAC_EVCTRL_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define DAC_EVCTRL_OFFSET 0x02 /**< \brief (DAC_EVCTRL offset) Event Control */ +#define DAC_EVCTRL_RESETVALUE _U_(0x00) /**< \brief (DAC_EVCTRL reset_value) Event Control */ + +#define DAC_EVCTRL_STARTEI0_Pos 0 /**< \brief (DAC_EVCTRL) Start Conversion Event Input DAC 0 */ +#define DAC_EVCTRL_STARTEI0 (_U_(1) << DAC_EVCTRL_STARTEI0_Pos) +#define DAC_EVCTRL_STARTEI1_Pos 1 /**< \brief (DAC_EVCTRL) Start Conversion Event Input DAC 1 */ +#define DAC_EVCTRL_STARTEI1 (_U_(1) << DAC_EVCTRL_STARTEI1_Pos) +#define DAC_EVCTRL_STARTEI_Pos 0 /**< \brief (DAC_EVCTRL) Start Conversion Event Input DAC x */ +#define DAC_EVCTRL_STARTEI_Msk (_U_(0x3) << DAC_EVCTRL_STARTEI_Pos) +#define DAC_EVCTRL_STARTEI(value) (DAC_EVCTRL_STARTEI_Msk & ((value) << DAC_EVCTRL_STARTEI_Pos)) +#define DAC_EVCTRL_EMPTYEO0_Pos 2 /**< \brief (DAC_EVCTRL) Data Buffer Empty Event Output DAC 0 */ +#define DAC_EVCTRL_EMPTYEO0 (_U_(1) << DAC_EVCTRL_EMPTYEO0_Pos) +#define DAC_EVCTRL_EMPTYEO1_Pos 3 /**< \brief (DAC_EVCTRL) Data Buffer Empty Event Output DAC 1 */ +#define DAC_EVCTRL_EMPTYEO1 (_U_(1) << DAC_EVCTRL_EMPTYEO1_Pos) +#define DAC_EVCTRL_EMPTYEO_Pos 2 /**< \brief (DAC_EVCTRL) Data Buffer Empty Event Output DAC x */ +#define DAC_EVCTRL_EMPTYEO_Msk (_U_(0x3) << DAC_EVCTRL_EMPTYEO_Pos) +#define DAC_EVCTRL_EMPTYEO(value) (DAC_EVCTRL_EMPTYEO_Msk & ((value) << DAC_EVCTRL_EMPTYEO_Pos)) +#define DAC_EVCTRL_INVEI0_Pos 4 /**< \brief (DAC_EVCTRL) Enable Invertion of DAC 0 input event */ +#define DAC_EVCTRL_INVEI0 (_U_(1) << DAC_EVCTRL_INVEI0_Pos) +#define DAC_EVCTRL_INVEI1_Pos 5 /**< \brief (DAC_EVCTRL) Enable Invertion of DAC 1 input event */ +#define DAC_EVCTRL_INVEI1 (_U_(1) << DAC_EVCTRL_INVEI1_Pos) +#define DAC_EVCTRL_INVEI_Pos 4 /**< \brief (DAC_EVCTRL) Enable Invertion of DAC x input event */ +#define DAC_EVCTRL_INVEI_Msk (_U_(0x3) << DAC_EVCTRL_INVEI_Pos) +#define DAC_EVCTRL_INVEI(value) (DAC_EVCTRL_INVEI_Msk & ((value) << DAC_EVCTRL_INVEI_Pos)) +#define DAC_EVCTRL_MASK _U_(0x3F) /**< \brief (DAC_EVCTRL) MASK Register */ + +/* -------- DAC_INTENCLR : (DAC Offset: 0x04) (R/W 8) Interrupt Enable Clear -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t UNDERRUN0:1; /*!< bit: 0 Underrun Interrupt Enable for DAC 0 */ + uint8_t UNDERRUN1:1; /*!< bit: 1 Underrun Interrupt Enable for DAC 1 */ + uint8_t EMPTY0:1; /*!< bit: 2 Data Buffer 0 Empty Interrupt Enable */ + uint8_t EMPTY1:1; /*!< bit: 3 Data Buffer 1 Empty Interrupt Enable */ + uint8_t :4; /*!< bit: 4.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + struct { + uint8_t UNDERRUN:2; /*!< bit: 0.. 1 Underrun Interrupt Enable for DAC x */ + uint8_t EMPTY:2; /*!< bit: 2.. 3 Data Buffer x Empty Interrupt Enable */ + uint8_t :4; /*!< bit: 4.. 7 Reserved */ + } vec; /*!< Structure used for vec access */ + uint8_t reg; /*!< Type used for register access */ +} DAC_INTENCLR_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define DAC_INTENCLR_OFFSET 0x04 /**< \brief (DAC_INTENCLR offset) Interrupt Enable Clear */ +#define DAC_INTENCLR_RESETVALUE _U_(0x00) /**< \brief (DAC_INTENCLR reset_value) Interrupt Enable Clear */ + +#define DAC_INTENCLR_UNDERRUN0_Pos 0 /**< \brief (DAC_INTENCLR) Underrun Interrupt Enable for DAC 0 */ +#define DAC_INTENCLR_UNDERRUN0 (_U_(1) << DAC_INTENCLR_UNDERRUN0_Pos) +#define DAC_INTENCLR_UNDERRUN1_Pos 1 /**< \brief (DAC_INTENCLR) Underrun Interrupt Enable for DAC 1 */ +#define DAC_INTENCLR_UNDERRUN1 (_U_(1) << DAC_INTENCLR_UNDERRUN1_Pos) +#define DAC_INTENCLR_UNDERRUN_Pos 0 /**< \brief (DAC_INTENCLR) Underrun Interrupt Enable for DAC x */ +#define DAC_INTENCLR_UNDERRUN_Msk (_U_(0x3) << DAC_INTENCLR_UNDERRUN_Pos) +#define DAC_INTENCLR_UNDERRUN(value) (DAC_INTENCLR_UNDERRUN_Msk & ((value) << DAC_INTENCLR_UNDERRUN_Pos)) +#define DAC_INTENCLR_EMPTY0_Pos 2 /**< \brief (DAC_INTENCLR) Data Buffer 0 Empty Interrupt Enable */ +#define DAC_INTENCLR_EMPTY0 (_U_(1) << DAC_INTENCLR_EMPTY0_Pos) +#define DAC_INTENCLR_EMPTY1_Pos 3 /**< \brief (DAC_INTENCLR) Data Buffer 1 Empty Interrupt Enable */ +#define DAC_INTENCLR_EMPTY1 (_U_(1) << DAC_INTENCLR_EMPTY1_Pos) +#define DAC_INTENCLR_EMPTY_Pos 2 /**< \brief (DAC_INTENCLR) Data Buffer x Empty Interrupt Enable */ +#define DAC_INTENCLR_EMPTY_Msk (_U_(0x3) << DAC_INTENCLR_EMPTY_Pos) +#define DAC_INTENCLR_EMPTY(value) (DAC_INTENCLR_EMPTY_Msk & ((value) << DAC_INTENCLR_EMPTY_Pos)) +#define DAC_INTENCLR_MASK _U_(0x0F) /**< \brief (DAC_INTENCLR) MASK Register */ + +/* -------- DAC_INTENSET : (DAC Offset: 0x05) (R/W 8) Interrupt Enable Set -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t UNDERRUN0:1; /*!< bit: 0 Underrun Interrupt Enable for DAC 0 */ + uint8_t UNDERRUN1:1; /*!< bit: 1 Underrun Interrupt Enable for DAC 1 */ + uint8_t EMPTY0:1; /*!< bit: 2 Data Buffer 0 Empty Interrupt Enable */ + uint8_t EMPTY1:1; /*!< bit: 3 Data Buffer 1 Empty Interrupt Enable */ + uint8_t :4; /*!< bit: 4.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + struct { + uint8_t UNDERRUN:2; /*!< bit: 0.. 1 Underrun Interrupt Enable for DAC x */ + uint8_t EMPTY:2; /*!< bit: 2.. 3 Data Buffer x Empty Interrupt Enable */ + uint8_t :4; /*!< bit: 4.. 7 Reserved */ + } vec; /*!< Structure used for vec access */ + uint8_t reg; /*!< Type used for register access */ +} DAC_INTENSET_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define DAC_INTENSET_OFFSET 0x05 /**< \brief (DAC_INTENSET offset) Interrupt Enable Set */ +#define DAC_INTENSET_RESETVALUE _U_(0x00) /**< \brief (DAC_INTENSET reset_value) Interrupt Enable Set */ + +#define DAC_INTENSET_UNDERRUN0_Pos 0 /**< \brief (DAC_INTENSET) Underrun Interrupt Enable for DAC 0 */ +#define DAC_INTENSET_UNDERRUN0 (_U_(1) << DAC_INTENSET_UNDERRUN0_Pos) +#define DAC_INTENSET_UNDERRUN1_Pos 1 /**< \brief (DAC_INTENSET) Underrun Interrupt Enable for DAC 1 */ +#define DAC_INTENSET_UNDERRUN1 (_U_(1) << DAC_INTENSET_UNDERRUN1_Pos) +#define DAC_INTENSET_UNDERRUN_Pos 0 /**< \brief (DAC_INTENSET) Underrun Interrupt Enable for DAC x */ +#define DAC_INTENSET_UNDERRUN_Msk (_U_(0x3) << DAC_INTENSET_UNDERRUN_Pos) +#define DAC_INTENSET_UNDERRUN(value) (DAC_INTENSET_UNDERRUN_Msk & ((value) << DAC_INTENSET_UNDERRUN_Pos)) +#define DAC_INTENSET_EMPTY0_Pos 2 /**< \brief (DAC_INTENSET) Data Buffer 0 Empty Interrupt Enable */ +#define DAC_INTENSET_EMPTY0 (_U_(1) << DAC_INTENSET_EMPTY0_Pos) +#define DAC_INTENSET_EMPTY1_Pos 3 /**< \brief (DAC_INTENSET) Data Buffer 1 Empty Interrupt Enable */ +#define DAC_INTENSET_EMPTY1 (_U_(1) << DAC_INTENSET_EMPTY1_Pos) +#define DAC_INTENSET_EMPTY_Pos 2 /**< \brief (DAC_INTENSET) Data Buffer x Empty Interrupt Enable */ +#define DAC_INTENSET_EMPTY_Msk (_U_(0x3) << DAC_INTENSET_EMPTY_Pos) +#define DAC_INTENSET_EMPTY(value) (DAC_INTENSET_EMPTY_Msk & ((value) << DAC_INTENSET_EMPTY_Pos)) +#define DAC_INTENSET_MASK _U_(0x0F) /**< \brief (DAC_INTENSET) MASK Register */ + +/* -------- DAC_INTFLAG : (DAC Offset: 0x06) (R/W 8) Interrupt Flag Status and Clear -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { // __I to avoid read-modify-write on write-to-clear register + struct { + __I uint8_t UNDERRUN0:1; /*!< bit: 0 DAC 0 Underrun */ + __I uint8_t UNDERRUN1:1; /*!< bit: 1 DAC 1 Underrun */ + __I uint8_t EMPTY0:1; /*!< bit: 2 Data Buffer 0 Empty */ + __I uint8_t EMPTY1:1; /*!< bit: 3 Data Buffer 1 Empty */ + __I uint8_t :4; /*!< bit: 4.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + struct { + __I uint8_t UNDERRUN:2; /*!< bit: 0.. 1 DAC x Underrun */ + __I uint8_t EMPTY:2; /*!< bit: 2.. 3 Data Buffer x Empty */ + __I uint8_t :4; /*!< bit: 4.. 7 Reserved */ + } vec; /*!< Structure used for vec access */ + uint8_t reg; /*!< Type used for register access */ +} DAC_INTFLAG_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define DAC_INTFLAG_OFFSET 0x06 /**< \brief (DAC_INTFLAG offset) Interrupt Flag Status and Clear */ +#define DAC_INTFLAG_RESETVALUE _U_(0x00) /**< \brief (DAC_INTFLAG reset_value) Interrupt Flag Status and Clear */ + +#define DAC_INTFLAG_UNDERRUN0_Pos 0 /**< \brief (DAC_INTFLAG) DAC 0 Underrun */ +#define DAC_INTFLAG_UNDERRUN0 (_U_(1) << DAC_INTFLAG_UNDERRUN0_Pos) +#define DAC_INTFLAG_UNDERRUN1_Pos 1 /**< \brief (DAC_INTFLAG) DAC 1 Underrun */ +#define DAC_INTFLAG_UNDERRUN1 (_U_(1) << DAC_INTFLAG_UNDERRUN1_Pos) +#define DAC_INTFLAG_UNDERRUN_Pos 0 /**< \brief (DAC_INTFLAG) DAC x Underrun */ +#define DAC_INTFLAG_UNDERRUN_Msk (_U_(0x3) << DAC_INTFLAG_UNDERRUN_Pos) +#define DAC_INTFLAG_UNDERRUN(value) (DAC_INTFLAG_UNDERRUN_Msk & ((value) << DAC_INTFLAG_UNDERRUN_Pos)) +#define DAC_INTFLAG_EMPTY0_Pos 2 /**< \brief (DAC_INTFLAG) Data Buffer 0 Empty */ +#define DAC_INTFLAG_EMPTY0 (_U_(1) << DAC_INTFLAG_EMPTY0_Pos) +#define DAC_INTFLAG_EMPTY1_Pos 3 /**< \brief (DAC_INTFLAG) Data Buffer 1 Empty */ +#define DAC_INTFLAG_EMPTY1 (_U_(1) << DAC_INTFLAG_EMPTY1_Pos) +#define DAC_INTFLAG_EMPTY_Pos 2 /**< \brief (DAC_INTFLAG) Data Buffer x Empty */ +#define DAC_INTFLAG_EMPTY_Msk (_U_(0x3) << DAC_INTFLAG_EMPTY_Pos) +#define DAC_INTFLAG_EMPTY(value) (DAC_INTFLAG_EMPTY_Msk & ((value) << DAC_INTFLAG_EMPTY_Pos)) +#define DAC_INTFLAG_MASK _U_(0x0F) /**< \brief (DAC_INTFLAG) MASK Register */ + +/* -------- DAC_STATUS : (DAC Offset: 0x07) (R/ 8) Status -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t READY0:1; /*!< bit: 0 DAC 0 Startup Ready */ + uint8_t READY1:1; /*!< bit: 1 DAC 1 Startup Ready */ + uint8_t EOC0:1; /*!< bit: 2 DAC 0 End of Conversion */ + uint8_t EOC1:1; /*!< bit: 3 DAC 1 End of Conversion */ + uint8_t :4; /*!< bit: 4.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + struct { + uint8_t READY:2; /*!< bit: 0.. 1 DAC x Startup Ready */ + uint8_t EOC:2; /*!< bit: 2.. 3 DAC x End of Conversion */ + uint8_t :4; /*!< bit: 4.. 7 Reserved */ + } vec; /*!< Structure used for vec access */ + uint8_t reg; /*!< Type used for register access */ +} DAC_STATUS_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define DAC_STATUS_OFFSET 0x07 /**< \brief (DAC_STATUS offset) Status */ +#define DAC_STATUS_RESETVALUE _U_(0x00) /**< \brief (DAC_STATUS reset_value) Status */ + +#define DAC_STATUS_READY0_Pos 0 /**< \brief (DAC_STATUS) DAC 0 Startup Ready */ +#define DAC_STATUS_READY0 (_U_(1) << DAC_STATUS_READY0_Pos) +#define DAC_STATUS_READY1_Pos 1 /**< \brief (DAC_STATUS) DAC 1 Startup Ready */ +#define DAC_STATUS_READY1 (_U_(1) << DAC_STATUS_READY1_Pos) +#define DAC_STATUS_READY_Pos 0 /**< \brief (DAC_STATUS) DAC x Startup Ready */ +#define DAC_STATUS_READY_Msk (_U_(0x3) << DAC_STATUS_READY_Pos) +#define DAC_STATUS_READY(value) (DAC_STATUS_READY_Msk & ((value) << DAC_STATUS_READY_Pos)) +#define DAC_STATUS_EOC0_Pos 2 /**< \brief (DAC_STATUS) DAC 0 End of Conversion */ +#define DAC_STATUS_EOC0 (_U_(1) << DAC_STATUS_EOC0_Pos) +#define DAC_STATUS_EOC1_Pos 3 /**< \brief (DAC_STATUS) DAC 1 End of Conversion */ +#define DAC_STATUS_EOC1 (_U_(1) << DAC_STATUS_EOC1_Pos) +#define DAC_STATUS_EOC_Pos 2 /**< \brief (DAC_STATUS) DAC x End of Conversion */ +#define DAC_STATUS_EOC_Msk (_U_(0x3) << DAC_STATUS_EOC_Pos) +#define DAC_STATUS_EOC(value) (DAC_STATUS_EOC_Msk & ((value) << DAC_STATUS_EOC_Pos)) +#define DAC_STATUS_MASK _U_(0x0F) /**< \brief (DAC_STATUS) MASK Register */ + +/* -------- DAC_SYNCBUSY : (DAC Offset: 0x08) (R/ 32) Synchronization Busy -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint32_t SWRST:1; /*!< bit: 0 Software Reset */ + uint32_t ENABLE:1; /*!< bit: 1 DAC Enable Status */ + uint32_t DATA0:1; /*!< bit: 2 Data DAC 0 */ + uint32_t DATA1:1; /*!< bit: 3 Data DAC 1 */ + uint32_t DATABUF0:1; /*!< bit: 4 Data Buffer DAC 0 */ + uint32_t DATABUF1:1; /*!< bit: 5 Data Buffer DAC 1 */ + uint32_t :26; /*!< bit: 6..31 Reserved */ + } bit; /*!< Structure used for bit access */ + struct { + uint32_t :2; /*!< bit: 0.. 1 Reserved */ + uint32_t DATA:2; /*!< bit: 2.. 3 Data DAC x */ + uint32_t DATABUF:2; /*!< bit: 4.. 5 Data Buffer DAC x */ + uint32_t :26; /*!< bit: 6..31 Reserved */ + } vec; /*!< Structure used for vec access */ + uint32_t reg; /*!< Type used for register access */ +} DAC_SYNCBUSY_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define DAC_SYNCBUSY_OFFSET 0x08 /**< \brief (DAC_SYNCBUSY offset) Synchronization Busy */ +#define DAC_SYNCBUSY_RESETVALUE _U_(0x00000000) /**< \brief (DAC_SYNCBUSY reset_value) Synchronization Busy */ + +#define DAC_SYNCBUSY_SWRST_Pos 0 /**< \brief (DAC_SYNCBUSY) Software Reset */ +#define DAC_SYNCBUSY_SWRST (_U_(0x1) << DAC_SYNCBUSY_SWRST_Pos) +#define DAC_SYNCBUSY_ENABLE_Pos 1 /**< \brief (DAC_SYNCBUSY) DAC Enable Status */ +#define DAC_SYNCBUSY_ENABLE (_U_(0x1) << DAC_SYNCBUSY_ENABLE_Pos) +#define DAC_SYNCBUSY_DATA0_Pos 2 /**< \brief (DAC_SYNCBUSY) Data DAC 0 */ +#define DAC_SYNCBUSY_DATA0 (_U_(1) << DAC_SYNCBUSY_DATA0_Pos) +#define DAC_SYNCBUSY_DATA1_Pos 3 /**< \brief (DAC_SYNCBUSY) Data DAC 1 */ +#define DAC_SYNCBUSY_DATA1 (_U_(1) << DAC_SYNCBUSY_DATA1_Pos) +#define DAC_SYNCBUSY_DATA_Pos 2 /**< \brief (DAC_SYNCBUSY) Data DAC x */ +#define DAC_SYNCBUSY_DATA_Msk (_U_(0x3) << DAC_SYNCBUSY_DATA_Pos) +#define DAC_SYNCBUSY_DATA(value) (DAC_SYNCBUSY_DATA_Msk & ((value) << DAC_SYNCBUSY_DATA_Pos)) +#define DAC_SYNCBUSY_DATABUF0_Pos 4 /**< \brief (DAC_SYNCBUSY) Data Buffer DAC 0 */ +#define DAC_SYNCBUSY_DATABUF0 (_U_(1) << DAC_SYNCBUSY_DATABUF0_Pos) +#define DAC_SYNCBUSY_DATABUF1_Pos 5 /**< \brief (DAC_SYNCBUSY) Data Buffer DAC 1 */ +#define DAC_SYNCBUSY_DATABUF1 (_U_(1) << DAC_SYNCBUSY_DATABUF1_Pos) +#define DAC_SYNCBUSY_DATABUF_Pos 4 /**< \brief (DAC_SYNCBUSY) Data Buffer DAC x */ +#define DAC_SYNCBUSY_DATABUF_Msk (_U_(0x3) << DAC_SYNCBUSY_DATABUF_Pos) +#define DAC_SYNCBUSY_DATABUF(value) (DAC_SYNCBUSY_DATABUF_Msk & ((value) << DAC_SYNCBUSY_DATABUF_Pos)) +#define DAC_SYNCBUSY_MASK _U_(0x0000003F) /**< \brief (DAC_SYNCBUSY) MASK Register */ + +/* -------- DAC_DACCTRL : (DAC Offset: 0x0C) (R/W 16) DAC n Control -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint16_t LEFTADJ:1; /*!< bit: 0 Left Adjusted Data */ + uint16_t ENABLE:1; /*!< bit: 1 Enable DAC0 */ + uint16_t CCTRL:2; /*!< bit: 2.. 3 Current Control */ + uint16_t :2; /*!< bit: 4.. 5 Reserved */ + uint16_t RUNSTDBY:1; /*!< bit: 6 Run in Standby */ + uint16_t DITHER:1; /*!< bit: 7 Dithering Mode */ + uint16_t REFRESH:4; /*!< bit: 8..11 Refresh period */ + uint16_t :4; /*!< bit: 12..15 Reserved */ + } bit; /*!< Structure used for bit access */ + uint16_t reg; /*!< Type used for register access */ +} DAC_DACCTRL_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define DAC_DACCTRL_OFFSET 0x0C /**< \brief (DAC_DACCTRL offset) DAC n Control */ +#define DAC_DACCTRL_RESETVALUE _U_(0x0000) /**< \brief (DAC_DACCTRL reset_value) DAC n Control */ + +#define DAC_DACCTRL_LEFTADJ_Pos 0 /**< \brief (DAC_DACCTRL) Left Adjusted Data */ +#define DAC_DACCTRL_LEFTADJ (_U_(0x1) << DAC_DACCTRL_LEFTADJ_Pos) +#define DAC_DACCTRL_ENABLE_Pos 1 /**< \brief (DAC_DACCTRL) Enable DAC0 */ +#define DAC_DACCTRL_ENABLE (_U_(0x1) << DAC_DACCTRL_ENABLE_Pos) +#define DAC_DACCTRL_CCTRL_Pos 2 /**< \brief (DAC_DACCTRL) Current Control */ +#define DAC_DACCTRL_CCTRL_Msk (_U_(0x3) << DAC_DACCTRL_CCTRL_Pos) +#define DAC_DACCTRL_CCTRL(value) (DAC_DACCTRL_CCTRL_Msk & ((value) << DAC_DACCTRL_CCTRL_Pos)) +#define DAC_DACCTRL_CCTRL_CC100K_Val _U_(0x0) /**< \brief (DAC_DACCTRL) GCLK_DAC <= 1.2MHz (100kSPS) */ +#define DAC_DACCTRL_CCTRL_CC1M_Val _U_(0x1) /**< \brief (DAC_DACCTRL) 1.2MHz < GCLK_DAC <= 6MHz (500kSPS) */ +#define DAC_DACCTRL_CCTRL_CC12M_Val _U_(0x2) /**< \brief (DAC_DACCTRL) 6MHz < GCLK_DAC <=12MHz (1MSPS) */ +#define DAC_DACCTRL_CCTRL_CC100K (DAC_DACCTRL_CCTRL_CC100K_Val << DAC_DACCTRL_CCTRL_Pos) +#define DAC_DACCTRL_CCTRL_CC1M (DAC_DACCTRL_CCTRL_CC1M_Val << DAC_DACCTRL_CCTRL_Pos) +#define DAC_DACCTRL_CCTRL_CC12M (DAC_DACCTRL_CCTRL_CC12M_Val << DAC_DACCTRL_CCTRL_Pos) +#define DAC_DACCTRL_RUNSTDBY_Pos 6 /**< \brief (DAC_DACCTRL) Run in Standby */ +#define DAC_DACCTRL_RUNSTDBY (_U_(0x1) << DAC_DACCTRL_RUNSTDBY_Pos) +#define DAC_DACCTRL_DITHER_Pos 7 /**< \brief (DAC_DACCTRL) Dithering Mode */ +#define DAC_DACCTRL_DITHER (_U_(0x1) << DAC_DACCTRL_DITHER_Pos) +#define DAC_DACCTRL_REFRESH_Pos 8 /**< \brief (DAC_DACCTRL) Refresh period */ +#define DAC_DACCTRL_REFRESH_Msk (_U_(0xF) << DAC_DACCTRL_REFRESH_Pos) +#define DAC_DACCTRL_REFRESH(value) (DAC_DACCTRL_REFRESH_Msk & ((value) << DAC_DACCTRL_REFRESH_Pos)) +#define DAC_DACCTRL_MASK _U_(0x0FCF) /**< \brief (DAC_DACCTRL) MASK Register */ + +/* -------- DAC_DATA : (DAC Offset: 0x10) ( /W 16) DAC n Data -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint16_t DATA:16; /*!< bit: 0..15 DAC0 Data */ + } bit; /*!< Structure used for bit access */ + uint16_t reg; /*!< Type used for register access */ +} DAC_DATA_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define DAC_DATA_OFFSET 0x10 /**< \brief (DAC_DATA offset) DAC n Data */ +#define DAC_DATA_RESETVALUE _U_(0x0000) /**< \brief (DAC_DATA reset_value) DAC n Data */ + +#define DAC_DATA_DATA_Pos 0 /**< \brief (DAC_DATA) DAC0 Data */ +#define DAC_DATA_DATA_Msk (_U_(0xFFFF) << DAC_DATA_DATA_Pos) +#define DAC_DATA_DATA(value) (DAC_DATA_DATA_Msk & ((value) << DAC_DATA_DATA_Pos)) +#define DAC_DATA_MASK _U_(0xFFFF) /**< \brief (DAC_DATA) MASK Register */ + +/* -------- DAC_DATABUF : (DAC Offset: 0x14) ( /W 16) DAC n Data Buffer -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint16_t DATABUF:16; /*!< bit: 0..15 DAC0 Data Buffer */ + } bit; /*!< Structure used for bit access */ + uint16_t reg; /*!< Type used for register access */ +} DAC_DATABUF_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define DAC_DATABUF_OFFSET 0x14 /**< \brief (DAC_DATABUF offset) DAC n Data Buffer */ +#define DAC_DATABUF_RESETVALUE _U_(0x0000) /**< \brief (DAC_DATABUF reset_value) DAC n Data Buffer */ + +#define DAC_DATABUF_DATABUF_Pos 0 /**< \brief (DAC_DATABUF) DAC0 Data Buffer */ +#define DAC_DATABUF_DATABUF_Msk (_U_(0xFFFF) << DAC_DATABUF_DATABUF_Pos) +#define DAC_DATABUF_DATABUF(value) (DAC_DATABUF_DATABUF_Msk & ((value) << DAC_DATABUF_DATABUF_Pos)) +#define DAC_DATABUF_MASK _U_(0xFFFF) /**< \brief (DAC_DATABUF) MASK Register */ + +/* -------- DAC_DBGCTRL : (DAC Offset: 0x18) (R/W 8) Debug Control -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t DBGRUN:1; /*!< bit: 0 Debug Run */ + uint8_t :7; /*!< bit: 1.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + uint8_t reg; /*!< Type used for register access */ +} DAC_DBGCTRL_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define DAC_DBGCTRL_OFFSET 0x18 /**< \brief (DAC_DBGCTRL offset) Debug Control */ +#define DAC_DBGCTRL_RESETVALUE _U_(0x00) /**< \brief (DAC_DBGCTRL reset_value) Debug Control */ + +#define DAC_DBGCTRL_DBGRUN_Pos 0 /**< \brief (DAC_DBGCTRL) Debug Run */ +#define DAC_DBGCTRL_DBGRUN (_U_(0x1) << DAC_DBGCTRL_DBGRUN_Pos) +#define DAC_DBGCTRL_MASK _U_(0x01) /**< \brief (DAC_DBGCTRL) MASK Register */ + +/** \brief DAC hardware registers */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef struct { + __IO DAC_CTRLA_Type CTRLA; /**< \brief Offset: 0x00 (R/W 8) Control A */ + __IO DAC_CTRLB_Type CTRLB; /**< \brief Offset: 0x01 (R/W 8) Control B */ + __IO DAC_EVCTRL_Type EVCTRL; /**< \brief Offset: 0x02 (R/W 8) Event Control */ + RoReg8 Reserved1[0x1]; + __IO DAC_INTENCLR_Type INTENCLR; /**< \brief Offset: 0x04 (R/W 8) Interrupt Enable Clear */ + __IO DAC_INTENSET_Type INTENSET; /**< \brief Offset: 0x05 (R/W 8) Interrupt Enable Set */ + __IO DAC_INTFLAG_Type INTFLAG; /**< \brief Offset: 0x06 (R/W 8) Interrupt Flag Status and Clear */ + __I DAC_STATUS_Type STATUS; /**< \brief Offset: 0x07 (R/ 8) Status */ + __I DAC_SYNCBUSY_Type SYNCBUSY; /**< \brief Offset: 0x08 (R/ 32) Synchronization Busy */ + __IO DAC_DACCTRL_Type DACCTRL[2]; /**< \brief Offset: 0x0C (R/W 16) DAC n Control */ + __O DAC_DATA_Type DATA[2]; /**< \brief Offset: 0x10 ( /W 16) DAC n Data */ + __O DAC_DATABUF_Type DATABUF[2]; /**< \brief Offset: 0x14 ( /W 16) DAC n Data Buffer */ + __IO DAC_DBGCTRL_Type DBGCTRL; /**< \brief Offset: 0x18 (R/W 8) Debug Control */ +} Dac; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +/*@}*/ + +#endif /* _SAMR34_DAC_COMPONENT_ */ diff --git a/src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/dmac.h b/src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/dmac.h new file mode 100644 index 000000000..217fdf850 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/component/dmac.h @@ -0,0 +1,1121 @@ +/** + * \file + * + * \brief Component description for DMAC + * + * Copyright (c) 2017 Microchip Technology Inc. + * + * \asf_license_start + * + * \page License + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the Licence at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * \asf_license_stop + * + */ + +#ifndef _SAMR34_DMAC_COMPONENT_ +#define _SAMR34_DMAC_COMPONENT_ + +/* ========================================================================== */ +/** SOFTWARE API DEFINITION FOR DMAC */ +/* ========================================================================== */ +/** \addtogroup SAMR34_DMAC Direct Memory Access Controller */ +/*@{*/ + +#define DMAC_U2223 +#define REV_DMAC 0x222 + +/* -------- DMAC_CTRL : (DMAC Offset: 0x00) (R/W 16) Control -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint16_t SWRST:1; /*!< bit: 0 Software Reset */ + uint16_t DMAENABLE:1; /*!< bit: 1 DMA Enable */ + uint16_t CRCENABLE:1; /*!< bit: 2 CRC Enable */ + uint16_t :5; /*!< bit: 3.. 7 Reserved */ + uint16_t LVLEN0:1; /*!< bit: 8 Priority Level 0 Enable */ + uint16_t LVLEN1:1; /*!< bit: 9 Priority Level 1 Enable */ + uint16_t LVLEN2:1; /*!< bit: 10 Priority Level 2 Enable */ + uint16_t LVLEN3:1; /*!< bit: 11 Priority Level 3 Enable */ + uint16_t :4; /*!< bit: 12..15 Reserved */ + } bit; /*!< Structure used for bit access */ + struct { + uint16_t :8; /*!< bit: 0.. 7 Reserved */ + uint16_t LVLEN:4; /*!< bit: 8..11 Priority Level x Enable */ + uint16_t :4; /*!< bit: 12..15 Reserved */ + } vec; /*!< Structure used for vec access */ + uint16_t reg; /*!< Type used for register access */ +} DMAC_CTRL_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define DMAC_CTRL_OFFSET 0x00 /**< \brief (DMAC_CTRL offset) Control */ +#define DMAC_CTRL_RESETVALUE _U_(0x0000) /**< \brief (DMAC_CTRL reset_value) Control */ + +#define DMAC_CTRL_SWRST_Pos 0 /**< \brief (DMAC_CTRL) Software Reset */ +#define DMAC_CTRL_SWRST (_U_(0x1) << DMAC_CTRL_SWRST_Pos) +#define DMAC_CTRL_DMAENABLE_Pos 1 /**< \brief (DMAC_CTRL) DMA Enable */ +#define DMAC_CTRL_DMAENABLE (_U_(0x1) << DMAC_CTRL_DMAENABLE_Pos) +#define DMAC_CTRL_CRCENABLE_Pos 2 /**< \brief (DMAC_CTRL) CRC Enable */ +#define DMAC_CTRL_CRCENABLE (_U_(0x1) << DMAC_CTRL_CRCENABLE_Pos) +#define DMAC_CTRL_LVLEN0_Pos 8 /**< \brief (DMAC_CTRL) Priority Level 0 Enable */ +#define DMAC_CTRL_LVLEN0 (_U_(1) << DMAC_CTRL_LVLEN0_Pos) +#define DMAC_CTRL_LVLEN1_Pos 9 /**< \brief (DMAC_CTRL) Priority Level 1 Enable */ +#define DMAC_CTRL_LVLEN1 (_U_(1) << DMAC_CTRL_LVLEN1_Pos) +#define DMAC_CTRL_LVLEN2_Pos 10 /**< \brief (DMAC_CTRL) Priority Level 2 Enable */ +#define DMAC_CTRL_LVLEN2 (_U_(1) << DMAC_CTRL_LVLEN2_Pos) +#define DMAC_CTRL_LVLEN3_Pos 11 /**< \brief (DMAC_CTRL) Priority Level 3 Enable */ +#define DMAC_CTRL_LVLEN3 (_U_(1) << DMAC_CTRL_LVLEN3_Pos) +#define DMAC_CTRL_LVLEN_Pos 8 /**< \brief (DMAC_CTRL) Priority Level x Enable */ +#define DMAC_CTRL_LVLEN_Msk (_U_(0xF) << DMAC_CTRL_LVLEN_Pos) +#define DMAC_CTRL_LVLEN(value) (DMAC_CTRL_LVLEN_Msk & ((value) << DMAC_CTRL_LVLEN_Pos)) +#define DMAC_CTRL_MASK _U_(0x0F07) /**< \brief (DMAC_CTRL) MASK Register */ + +/* -------- DMAC_CRCCTRL : (DMAC Offset: 0x02) (R/W 16) CRC Control -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint16_t CRCBEATSIZE:2; /*!< bit: 0.. 1 CRC Beat Size */ + uint16_t CRCPOLY:2; /*!< bit: 2.. 3 CRC Polynomial Type */ + uint16_t :4; /*!< bit: 4.. 7 Reserved */ + uint16_t CRCSRC:6; /*!< bit: 8..13 CRC Input Source */ + uint16_t :2; /*!< bit: 14..15 Reserved */ + } bit; /*!< Structure used for bit access */ + uint16_t reg; /*!< Type used for register access */ +} DMAC_CRCCTRL_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define DMAC_CRCCTRL_OFFSET 0x02 /**< \brief (DMAC_CRCCTRL offset) CRC Control */ +#define DMAC_CRCCTRL_RESETVALUE _U_(0x0000) /**< \brief (DMAC_CRCCTRL reset_value) CRC Control */ + +#define DMAC_CRCCTRL_CRCBEATSIZE_Pos 0 /**< \brief (DMAC_CRCCTRL) CRC Beat Size */ +#define DMAC_CRCCTRL_CRCBEATSIZE_Msk (_U_(0x3) << DMAC_CRCCTRL_CRCBEATSIZE_Pos) +#define DMAC_CRCCTRL_CRCBEATSIZE(value) (DMAC_CRCCTRL_CRCBEATSIZE_Msk & ((value) << DMAC_CRCCTRL_CRCBEATSIZE_Pos)) +#define DMAC_CRCCTRL_CRCBEATSIZE_BYTE_Val _U_(0x0) /**< \brief (DMAC_CRCCTRL) 8-bit bus transfer */ +#define DMAC_CRCCTRL_CRCBEATSIZE_HWORD_Val _U_(0x1) /**< \brief (DMAC_CRCCTRL) 16-bit bus transfer */ +#define DMAC_CRCCTRL_CRCBEATSIZE_WORD_Val _U_(0x2) /**< \brief (DMAC_CRCCTRL) 32-bit bus transfer */ +#define DMAC_CRCCTRL_CRCBEATSIZE_BYTE (DMAC_CRCCTRL_CRCBEATSIZE_BYTE_Val << DMAC_CRCCTRL_CRCBEATSIZE_Pos) +#define DMAC_CRCCTRL_CRCBEATSIZE_HWORD (DMAC_CRCCTRL_CRCBEATSIZE_HWORD_Val << DMAC_CRCCTRL_CRCBEATSIZE_Pos) +#define DMAC_CRCCTRL_CRCBEATSIZE_WORD (DMAC_CRCCTRL_CRCBEATSIZE_WORD_Val << DMAC_CRCCTRL_CRCBEATSIZE_Pos) +#define DMAC_CRCCTRL_CRCPOLY_Pos 2 /**< \brief (DMAC_CRCCTRL) CRC Polynomial Type */ +#define DMAC_CRCCTRL_CRCPOLY_Msk (_U_(0x3) << DMAC_CRCCTRL_CRCPOLY_Pos) +#define DMAC_CRCCTRL_CRCPOLY(value) (DMAC_CRCCTRL_CRCPOLY_Msk & ((value) << DMAC_CRCCTRL_CRCPOLY_Pos)) +#define DMAC_CRCCTRL_CRCPOLY_CRC16_Val _U_(0x0) /**< \brief (DMAC_CRCCTRL) CRC-16 (CRC-CCITT) */ +#define DMAC_CRCCTRL_CRCPOLY_CRC32_Val _U_(0x1) /**< \brief (DMAC_CRCCTRL) CRC32 (IEEE 802.3) */ +#define DMAC_CRCCTRL_CRCPOLY_CRC16 (DMAC_CRCCTRL_CRCPOLY_CRC16_Val << DMAC_CRCCTRL_CRCPOLY_Pos) +#define DMAC_CRCCTRL_CRCPOLY_CRC32 (DMAC_CRCCTRL_CRCPOLY_CRC32_Val << DMAC_CRCCTRL_CRCPOLY_Pos) +#define DMAC_CRCCTRL_CRCSRC_Pos 8 /**< \brief (DMAC_CRCCTRL) CRC Input Source */ +#define DMAC_CRCCTRL_CRCSRC_Msk (_U_(0x3F) << DMAC_CRCCTRL_CRCSRC_Pos) +#define DMAC_CRCCTRL_CRCSRC(value) (DMAC_CRCCTRL_CRCSRC_Msk & ((value) << DMAC_CRCCTRL_CRCSRC_Pos)) +#define DMAC_CRCCTRL_CRCSRC_NOACT_Val _U_(0x0) /**< \brief (DMAC_CRCCTRL) No action */ +#define DMAC_CRCCTRL_CRCSRC_IO_Val _U_(0x1) /**< \brief (DMAC_CRCCTRL) I/O interface */ +#define DMAC_CRCCTRL_CRCSRC_NOACT (DMAC_CRCCTRL_CRCSRC_NOACT_Val << DMAC_CRCCTRL_CRCSRC_Pos) +#define DMAC_CRCCTRL_CRCSRC_IO (DMAC_CRCCTRL_CRCSRC_IO_Val << DMAC_CRCCTRL_CRCSRC_Pos) +#define DMAC_CRCCTRL_MASK _U_(0x3F0F) /**< \brief (DMAC_CRCCTRL) MASK Register */ + +/* -------- DMAC_CRCDATAIN : (DMAC Offset: 0x04) (R/W 32) CRC Data Input -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint32_t CRCDATAIN:32; /*!< bit: 0..31 CRC Data Input */ + } bit; /*!< Structure used for bit access */ + uint32_t reg; /*!< Type used for register access */ +} DMAC_CRCDATAIN_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define DMAC_CRCDATAIN_OFFSET 0x04 /**< \brief (DMAC_CRCDATAIN offset) CRC Data Input */ +#define DMAC_CRCDATAIN_RESETVALUE _U_(0x00000000) /**< \brief (DMAC_CRCDATAIN reset_value) CRC Data Input */ + +#define DMAC_CRCDATAIN_CRCDATAIN_Pos 0 /**< \brief (DMAC_CRCDATAIN) CRC Data Input */ +#define DMAC_CRCDATAIN_CRCDATAIN_Msk (_U_(0xFFFFFFFF) << DMAC_CRCDATAIN_CRCDATAIN_Pos) +#define DMAC_CRCDATAIN_CRCDATAIN(value) (DMAC_CRCDATAIN_CRCDATAIN_Msk & ((value) << DMAC_CRCDATAIN_CRCDATAIN_Pos)) +#define DMAC_CRCDATAIN_MASK _U_(0xFFFFFFFF) /**< \brief (DMAC_CRCDATAIN) MASK Register */ + +/* -------- DMAC_CRCCHKSUM : (DMAC Offset: 0x08) (R/W 32) CRC Checksum -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint32_t CRCCHKSUM:32; /*!< bit: 0..31 CRC Checksum */ + } bit; /*!< Structure used for bit access */ + uint32_t reg; /*!< Type used for register access */ +} DMAC_CRCCHKSUM_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define DMAC_CRCCHKSUM_OFFSET 0x08 /**< \brief (DMAC_CRCCHKSUM offset) CRC Checksum */ +#define DMAC_CRCCHKSUM_RESETVALUE _U_(0x00000000) /**< \brief (DMAC_CRCCHKSUM reset_value) CRC Checksum */ + +#define DMAC_CRCCHKSUM_CRCCHKSUM_Pos 0 /**< \brief (DMAC_CRCCHKSUM) CRC Checksum */ +#define DMAC_CRCCHKSUM_CRCCHKSUM_Msk (_U_(0xFFFFFFFF) << DMAC_CRCCHKSUM_CRCCHKSUM_Pos) +#define DMAC_CRCCHKSUM_CRCCHKSUM(value) (DMAC_CRCCHKSUM_CRCCHKSUM_Msk & ((value) << DMAC_CRCCHKSUM_CRCCHKSUM_Pos)) +#define DMAC_CRCCHKSUM_MASK _U_(0xFFFFFFFF) /**< \brief (DMAC_CRCCHKSUM) MASK Register */ + +/* -------- DMAC_CRCSTATUS : (DMAC Offset: 0x0C) (R/W 8) CRC Status -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t CRCBUSY:1; /*!< bit: 0 CRC Module Busy */ + uint8_t CRCZERO:1; /*!< bit: 1 CRC Zero */ + uint8_t :6; /*!< bit: 2.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + uint8_t reg; /*!< Type used for register access */ +} DMAC_CRCSTATUS_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define DMAC_CRCSTATUS_OFFSET 0x0C /**< \brief (DMAC_CRCSTATUS offset) CRC Status */ +#define DMAC_CRCSTATUS_RESETVALUE _U_(0x00) /**< \brief (DMAC_CRCSTATUS reset_value) CRC Status */ + +#define DMAC_CRCSTATUS_CRCBUSY_Pos 0 /**< \brief (DMAC_CRCSTATUS) CRC Module Busy */ +#define DMAC_CRCSTATUS_CRCBUSY (_U_(0x1) << DMAC_CRCSTATUS_CRCBUSY_Pos) +#define DMAC_CRCSTATUS_CRCZERO_Pos 1 /**< \brief (DMAC_CRCSTATUS) CRC Zero */ +#define DMAC_CRCSTATUS_CRCZERO (_U_(0x1) << DMAC_CRCSTATUS_CRCZERO_Pos) +#define DMAC_CRCSTATUS_MASK _U_(0x03) /**< \brief (DMAC_CRCSTATUS) MASK Register */ + +/* -------- DMAC_DBGCTRL : (DMAC Offset: 0x0D) (R/W 8) Debug Control -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t DBGRUN:1; /*!< bit: 0 Debug Run */ + uint8_t :7; /*!< bit: 1.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + uint8_t reg; /*!< Type used for register access */ +} DMAC_DBGCTRL_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define DMAC_DBGCTRL_OFFSET 0x0D /**< \brief (DMAC_DBGCTRL offset) Debug Control */ +#define DMAC_DBGCTRL_RESETVALUE _U_(0x00) /**< \brief (DMAC_DBGCTRL reset_value) Debug Control */ + +#define DMAC_DBGCTRL_DBGRUN_Pos 0 /**< \brief (DMAC_DBGCTRL) Debug Run */ +#define DMAC_DBGCTRL_DBGRUN (_U_(0x1) << DMAC_DBGCTRL_DBGRUN_Pos) +#define DMAC_DBGCTRL_MASK _U_(0x01) /**< \brief (DMAC_DBGCTRL) MASK Register */ + +/* -------- DMAC_QOSCTRL : (DMAC Offset: 0x0E) (R/W 8) QOS Control -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t WRBQOS:2; /*!< bit: 0.. 1 Write-Back Quality of Service */ + uint8_t FQOS:2; /*!< bit: 2.. 3 Fetch Quality of Service */ + uint8_t DQOS:2; /*!< bit: 4.. 5 Data Transfer Quality of Service */ + uint8_t :2; /*!< bit: 6.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + uint8_t reg; /*!< Type used for register access */ +} DMAC_QOSCTRL_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define DMAC_QOSCTRL_OFFSET 0x0E /**< \brief (DMAC_QOSCTRL offset) QOS Control */ +#define DMAC_QOSCTRL_RESETVALUE _U_(0x2A) /**< \brief (DMAC_QOSCTRL reset_value) QOS Control */ + +#define DMAC_QOSCTRL_WRBQOS_Pos 0 /**< \brief (DMAC_QOSCTRL) Write-Back Quality of Service */ +#define DMAC_QOSCTRL_WRBQOS_Msk (_U_(0x3) << DMAC_QOSCTRL_WRBQOS_Pos) +#define DMAC_QOSCTRL_WRBQOS(value) (DMAC_QOSCTRL_WRBQOS_Msk & ((value) << DMAC_QOSCTRL_WRBQOS_Pos)) +#define DMAC_QOSCTRL_WRBQOS_DISABLE_Val _U_(0x0) /**< \brief (DMAC_QOSCTRL) Background (no sensitive operation) */ +#define DMAC_QOSCTRL_WRBQOS_LOW_Val _U_(0x1) /**< \brief (DMAC_QOSCTRL) Sensitive Bandwidth */ +#define DMAC_QOSCTRL_WRBQOS_MEDIUM_Val _U_(0x2) /**< \brief (DMAC_QOSCTRL) Sensitive Latency */ +#define DMAC_QOSCTRL_WRBQOS_HIGH_Val _U_(0x3) /**< \brief (DMAC_QOSCTRL) Critical Latency */ +#define DMAC_QOSCTRL_WRBQOS_DISABLE (DMAC_QOSCTRL_WRBQOS_DISABLE_Val << DMAC_QOSCTRL_WRBQOS_Pos) +#define DMAC_QOSCTRL_WRBQOS_LOW (DMAC_QOSCTRL_WRBQOS_LOW_Val << DMAC_QOSCTRL_WRBQOS_Pos) +#define DMAC_QOSCTRL_WRBQOS_MEDIUM (DMAC_QOSCTRL_WRBQOS_MEDIUM_Val << DMAC_QOSCTRL_WRBQOS_Pos) +#define DMAC_QOSCTRL_WRBQOS_HIGH (DMAC_QOSCTRL_WRBQOS_HIGH_Val << DMAC_QOSCTRL_WRBQOS_Pos) +#define DMAC_QOSCTRL_FQOS_Pos 2 /**< \brief (DMAC_QOSCTRL) Fetch Quality of Service */ +#define DMAC_QOSCTRL_FQOS_Msk (_U_(0x3) << DMAC_QOSCTRL_FQOS_Pos) +#define DMAC_QOSCTRL_FQOS(value) (DMAC_QOSCTRL_FQOS_Msk & ((value) << DMAC_QOSCTRL_FQOS_Pos)) +#define DMAC_QOSCTRL_FQOS_DISABLE_Val _U_(0x0) /**< \brief (DMAC_QOSCTRL) Background (no sensitive operation) */ +#define DMAC_QOSCTRL_FQOS_LOW_Val _U_(0x1) /**< \brief (DMAC_QOSCTRL) Sensitive Bandwidth */ +#define DMAC_QOSCTRL_FQOS_MEDIUM_Val _U_(0x2) /**< \brief (DMAC_QOSCTRL) Sensitive Latency */ +#define DMAC_QOSCTRL_FQOS_HIGH_Val _U_(0x3) /**< \brief (DMAC_QOSCTRL) Critical Latency */ +#define DMAC_QOSCTRL_FQOS_DISABLE (DMAC_QOSCTRL_FQOS_DISABLE_Val << DMAC_QOSCTRL_FQOS_Pos) +#define DMAC_QOSCTRL_FQOS_LOW (DMAC_QOSCTRL_FQOS_LOW_Val << DMAC_QOSCTRL_FQOS_Pos) +#define DMAC_QOSCTRL_FQOS_MEDIUM (DMAC_QOSCTRL_FQOS_MEDIUM_Val << DMAC_QOSCTRL_FQOS_Pos) +#define DMAC_QOSCTRL_FQOS_HIGH (DMAC_QOSCTRL_FQOS_HIGH_Val << DMAC_QOSCTRL_FQOS_Pos) +#define DMAC_QOSCTRL_DQOS_Pos 4 /**< \brief (DMAC_QOSCTRL) Data Transfer Quality of Service */ +#define DMAC_QOSCTRL_DQOS_Msk (_U_(0x3) << DMAC_QOSCTRL_DQOS_Pos) +#define DMAC_QOSCTRL_DQOS(value) (DMAC_QOSCTRL_DQOS_Msk & ((value) << DMAC_QOSCTRL_DQOS_Pos)) +#define DMAC_QOSCTRL_DQOS_DISABLE_Val _U_(0x0) /**< \brief (DMAC_QOSCTRL) Background (no sensitive operation) */ +#define DMAC_QOSCTRL_DQOS_LOW_Val _U_(0x1) /**< \brief (DMAC_QOSCTRL) Sensitive Bandwidth */ +#define DMAC_QOSCTRL_DQOS_MEDIUM_Val _U_(0x2) /**< \brief (DMAC_QOSCTRL) Sensitive Latency */ +#define DMAC_QOSCTRL_DQOS_HIGH_Val _U_(0x3) /**< \brief (DMAC_QOSCTRL) Critical Latency */ +#define DMAC_QOSCTRL_DQOS_DISABLE (DMAC_QOSCTRL_DQOS_DISABLE_Val << DMAC_QOSCTRL_DQOS_Pos) +#define DMAC_QOSCTRL_DQOS_LOW (DMAC_QOSCTRL_DQOS_LOW_Val << DMAC_QOSCTRL_DQOS_Pos) +#define DMAC_QOSCTRL_DQOS_MEDIUM (DMAC_QOSCTRL_DQOS_MEDIUM_Val << DMAC_QOSCTRL_DQOS_Pos) +#define DMAC_QOSCTRL_DQOS_HIGH (DMAC_QOSCTRL_DQOS_HIGH_Val << DMAC_QOSCTRL_DQOS_Pos) +#define DMAC_QOSCTRL_MASK _U_(0x3F) /**< \brief (DMAC_QOSCTRL) MASK Register */ + +/* -------- DMAC_SWTRIGCTRL : (DMAC Offset: 0x10) (R/W 32) Software Trigger Control -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint32_t SWTRIG0:1; /*!< bit: 0 Channel 0 Software Trigger */ + uint32_t SWTRIG1:1; /*!< bit: 1 Channel 1 Software Trigger */ + uint32_t SWTRIG2:1; /*!< bit: 2 Channel 2 Software Trigger */ + uint32_t SWTRIG3:1; /*!< bit: 3 Channel 3 Software Trigger */ + uint32_t SWTRIG4:1; /*!< bit: 4 Channel 4 Software Trigger */ + uint32_t SWTRIG5:1; /*!< bit: 5 Channel 5 Software Trigger */ + uint32_t SWTRIG6:1; /*!< bit: 6 Channel 6 Software Trigger */ + uint32_t SWTRIG7:1; /*!< bit: 7 Channel 7 Software Trigger */ + uint32_t SWTRIG8:1; /*!< bit: 8 Channel 8 Software Trigger */ + uint32_t SWTRIG9:1; /*!< bit: 9 Channel 9 Software Trigger */ + uint32_t SWTRIG10:1; /*!< bit: 10 Channel 10 Software Trigger */ + uint32_t SWTRIG11:1; /*!< bit: 11 Channel 11 Software Trigger */ + uint32_t SWTRIG12:1; /*!< bit: 12 Channel 12 Software Trigger */ + uint32_t SWTRIG13:1; /*!< bit: 13 Channel 13 Software Trigger */ + uint32_t SWTRIG14:1; /*!< bit: 14 Channel 14 Software Trigger */ + uint32_t SWTRIG15:1; /*!< bit: 15 Channel 15 Software Trigger */ + uint32_t :16; /*!< bit: 16..31 Reserved */ + } bit; /*!< Structure used for bit access */ + struct { + uint32_t SWTRIG:16; /*!< bit: 0..15 Channel x Software Trigger */ + uint32_t :16; /*!< bit: 16..31 Reserved */ + } vec; /*!< Structure used for vec access */ + uint32_t reg; /*!< Type used for register access */ +} DMAC_SWTRIGCTRL_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define DMAC_SWTRIGCTRL_OFFSET 0x10 /**< \brief (DMAC_SWTRIGCTRL offset) Software Trigger Control */ +#define DMAC_SWTRIGCTRL_RESETVALUE _U_(0x00000000) /**< \brief (DMAC_SWTRIGCTRL reset_value) Software Trigger Control */ + +#define DMAC_SWTRIGCTRL_SWTRIG0_Pos 0 /**< \brief (DMAC_SWTRIGCTRL) Channel 0 Software Trigger */ +#define DMAC_SWTRIGCTRL_SWTRIG0 (_U_(1) << DMAC_SWTRIGCTRL_SWTRIG0_Pos) +#define DMAC_SWTRIGCTRL_SWTRIG1_Pos 1 /**< \brief (DMAC_SWTRIGCTRL) Channel 1 Software Trigger */ +#define DMAC_SWTRIGCTRL_SWTRIG1 (_U_(1) << DMAC_SWTRIGCTRL_SWTRIG1_Pos) +#define DMAC_SWTRIGCTRL_SWTRIG2_Pos 2 /**< \brief (DMAC_SWTRIGCTRL) Channel 2 Software Trigger */ +#define DMAC_SWTRIGCTRL_SWTRIG2 (_U_(1) << DMAC_SWTRIGCTRL_SWTRIG2_Pos) +#define DMAC_SWTRIGCTRL_SWTRIG3_Pos 3 /**< \brief (DMAC_SWTRIGCTRL) Channel 3 Software Trigger */ +#define DMAC_SWTRIGCTRL_SWTRIG3 (_U_(1) << DMAC_SWTRIGCTRL_SWTRIG3_Pos) +#define DMAC_SWTRIGCTRL_SWTRIG4_Pos 4 /**< \brief (DMAC_SWTRIGCTRL) Channel 4 Software Trigger */ +#define DMAC_SWTRIGCTRL_SWTRIG4 (_U_(1) << DMAC_SWTRIGCTRL_SWTRIG4_Pos) +#define DMAC_SWTRIGCTRL_SWTRIG5_Pos 5 /**< \brief (DMAC_SWTRIGCTRL) Channel 5 Software Trigger */ +#define DMAC_SWTRIGCTRL_SWTRIG5 (_U_(1) << DMAC_SWTRIGCTRL_SWTRIG5_Pos) +#define DMAC_SWTRIGCTRL_SWTRIG6_Pos 6 /**< \brief (DMAC_SWTRIGCTRL) Channel 6 Software Trigger */ +#define DMAC_SWTRIGCTRL_SWTRIG6 (_U_(1) << DMAC_SWTRIGCTRL_SWTRIG6_Pos) +#define DMAC_SWTRIGCTRL_SWTRIG7_Pos 7 /**< \brief (DMAC_SWTRIGCTRL) Channel 7 Software Trigger */ +#define DMAC_SWTRIGCTRL_SWTRIG7 (_U_(1) << DMAC_SWTRIGCTRL_SWTRIG7_Pos) +#define DMAC_SWTRIGCTRL_SWTRIG8_Pos 8 /**< \brief (DMAC_SWTRIGCTRL) Channel 8 Software Trigger */ +#define DMAC_SWTRIGCTRL_SWTRIG8 (_U_(1) << DMAC_SWTRIGCTRL_SWTRIG8_Pos) +#define DMAC_SWTRIGCTRL_SWTRIG9_Pos 9 /**< \brief (DMAC_SWTRIGCTRL) Channel 9 Software Trigger */ +#define DMAC_SWTRIGCTRL_SWTRIG9 (_U_(1) << DMAC_SWTRIGCTRL_SWTRIG9_Pos) +#define DMAC_SWTRIGCTRL_SWTRIG10_Pos 10 /**< \brief (DMAC_SWTRIGCTRL) Channel 10 Software Trigger */ +#define DMAC_SWTRIGCTRL_SWTRIG10 (_U_(1) << DMAC_SWTRIGCTRL_SWTRIG10_Pos) +#define DMAC_SWTRIGCTRL_SWTRIG11_Pos 11 /**< \brief (DMAC_SWTRIGCTRL) Channel 11 Software Trigger */ +#define DMAC_SWTRIGCTRL_SWTRIG11 (_U_(1) << DMAC_SWTRIGCTRL_SWTRIG11_Pos) +#define DMAC_SWTRIGCTRL_SWTRIG12_Pos 12 /**< \brief (DMAC_SWTRIGCTRL) Channel 12 Software Trigger */ +#define DMAC_SWTRIGCTRL_SWTRIG12 (_U_(1) << DMAC_SWTRIGCTRL_SWTRIG12_Pos) +#define DMAC_SWTRIGCTRL_SWTRIG13_Pos 13 /**< \brief (DMAC_SWTRIGCTRL) Channel 13 Software Trigger */ +#define DMAC_SWTRIGCTRL_SWTRIG13 (_U_(1) << DMAC_SWTRIGCTRL_SWTRIG13_Pos) +#define DMAC_SWTRIGCTRL_SWTRIG14_Pos 14 /**< \brief (DMAC_SWTRIGCTRL) Channel 14 Software Trigger */ +#define DMAC_SWTRIGCTRL_SWTRIG14 (_U_(1) << DMAC_SWTRIGCTRL_SWTRIG14_Pos) +#define DMAC_SWTRIGCTRL_SWTRIG15_Pos 15 /**< \brief (DMAC_SWTRIGCTRL) Channel 15 Software Trigger */ +#define DMAC_SWTRIGCTRL_SWTRIG15 (_U_(1) << DMAC_SWTRIGCTRL_SWTRIG15_Pos) +#define DMAC_SWTRIGCTRL_SWTRIG_Pos 0 /**< \brief (DMAC_SWTRIGCTRL) Channel x Software Trigger */ +#define DMAC_SWTRIGCTRL_SWTRIG_Msk (_U_(0xFFFF) << DMAC_SWTRIGCTRL_SWTRIG_Pos) +#define DMAC_SWTRIGCTRL_SWTRIG(value) (DMAC_SWTRIGCTRL_SWTRIG_Msk & ((value) << DMAC_SWTRIGCTRL_SWTRIG_Pos)) +#define DMAC_SWTRIGCTRL_MASK _U_(0x0000FFFF) /**< \brief (DMAC_SWTRIGCTRL) MASK Register */ + +/* -------- DMAC_PRICTRL0 : (DMAC Offset: 0x14) (R/W 32) Priority Control 0 -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint32_t LVLPRI0:4; /*!< bit: 0.. 3 Level 0 Channel Priority Number */ + uint32_t :3; /*!< bit: 4.. 6 Reserved */ + uint32_t RRLVLEN0:1; /*!< bit: 7 Level 0 Round-Robin Scheduling Enable */ + uint32_t LVLPRI1:4; /*!< bit: 8..11 Level 1 Channel Priority Number */ + uint32_t :3; /*!< bit: 12..14 Reserved */ + uint32_t RRLVLEN1:1; /*!< bit: 15 Level 1 Round-Robin Scheduling Enable */ + uint32_t LVLPRI2:4; /*!< bit: 16..19 Level 2 Channel Priority Number */ + uint32_t :3; /*!< bit: 20..22 Reserved */ + uint32_t RRLVLEN2:1; /*!< bit: 23 Level 2 Round-Robin Scheduling Enable */ + uint32_t LVLPRI3:4; /*!< bit: 24..27 Level 3 Channel Priority Number */ + uint32_t :3; /*!< bit: 28..30 Reserved */ + uint32_t RRLVLEN3:1; /*!< bit: 31 Level 3 Round-Robin Scheduling Enable */ + } bit; /*!< Structure used for bit access */ + uint32_t reg; /*!< Type used for register access */ +} DMAC_PRICTRL0_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define DMAC_PRICTRL0_OFFSET 0x14 /**< \brief (DMAC_PRICTRL0 offset) Priority Control 0 */ +#define DMAC_PRICTRL0_RESETVALUE _U_(0x00000000) /**< \brief (DMAC_PRICTRL0 reset_value) Priority Control 0 */ + +#define DMAC_PRICTRL0_LVLPRI0_Pos 0 /**< \brief (DMAC_PRICTRL0) Level 0 Channel Priority Number */ +#define DMAC_PRICTRL0_LVLPRI0_Msk (_U_(0xF) << DMAC_PRICTRL0_LVLPRI0_Pos) +#define DMAC_PRICTRL0_LVLPRI0(value) (DMAC_PRICTRL0_LVLPRI0_Msk & ((value) << DMAC_PRICTRL0_LVLPRI0_Pos)) +#define DMAC_PRICTRL0_RRLVLEN0_Pos 7 /**< \brief (DMAC_PRICTRL0) Level 0 Round-Robin Scheduling Enable */ +#define DMAC_PRICTRL0_RRLVLEN0 (_U_(0x1) << DMAC_PRICTRL0_RRLVLEN0_Pos) +#define DMAC_PRICTRL0_LVLPRI1_Pos 8 /**< \brief (DMAC_PRICTRL0) Level 1 Channel Priority Number */ +#define DMAC_PRICTRL0_LVLPRI1_Msk (_U_(0xF) << DMAC_PRICTRL0_LVLPRI1_Pos) +#define DMAC_PRICTRL0_LVLPRI1(value) (DMAC_PRICTRL0_LVLPRI1_Msk & ((value) << DMAC_PRICTRL0_LVLPRI1_Pos)) +#define DMAC_PRICTRL0_RRLVLEN1_Pos 15 /**< \brief (DMAC_PRICTRL0) Level 1 Round-Robin Scheduling Enable */ +#define DMAC_PRICTRL0_RRLVLEN1 (_U_(0x1) << DMAC_PRICTRL0_RRLVLEN1_Pos) +#define DMAC_PRICTRL0_LVLPRI2_Pos 16 /**< \brief (DMAC_PRICTRL0) Level 2 Channel Priority Number */ +#define DMAC_PRICTRL0_LVLPRI2_Msk (_U_(0xF) << DMAC_PRICTRL0_LVLPRI2_Pos) +#define DMAC_PRICTRL0_LVLPRI2(value) (DMAC_PRICTRL0_LVLPRI2_Msk & ((value) << DMAC_PRICTRL0_LVLPRI2_Pos)) +#define DMAC_PRICTRL0_RRLVLEN2_Pos 23 /**< \brief (DMAC_PRICTRL0) Level 2 Round-Robin Scheduling Enable */ +#define DMAC_PRICTRL0_RRLVLEN2 (_U_(0x1) << DMAC_PRICTRL0_RRLVLEN2_Pos) +#define DMAC_PRICTRL0_LVLPRI3_Pos 24 /**< \brief (DMAC_PRICTRL0) Level 3 Channel Priority Number */ +#define DMAC_PRICTRL0_LVLPRI3_Msk (_U_(0xF) << DMAC_PRICTRL0_LVLPRI3_Pos) +#define DMAC_PRICTRL0_LVLPRI3(value) (DMAC_PRICTRL0_LVLPRI3_Msk & ((value) << DMAC_PRICTRL0_LVLPRI3_Pos)) +#define DMAC_PRICTRL0_RRLVLEN3_Pos 31 /**< \brief (DMAC_PRICTRL0) Level 3 Round-Robin Scheduling Enable */ +#define DMAC_PRICTRL0_RRLVLEN3 (_U_(0x1) << DMAC_PRICTRL0_RRLVLEN3_Pos) +#define DMAC_PRICTRL0_MASK _U_(0x8F8F8F8F) /**< \brief (DMAC_PRICTRL0) MASK Register */ + +/* -------- DMAC_INTPEND : (DMAC Offset: 0x20) (R/W 16) Interrupt Pending -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint16_t ID:4; /*!< bit: 0.. 3 Channel ID */ + uint16_t :4; /*!< bit: 4.. 7 Reserved */ + uint16_t TERR:1; /*!< bit: 8 Transfer Error */ + uint16_t TCMPL:1; /*!< bit: 9 Transfer Complete */ + uint16_t SUSP:1; /*!< bit: 10 Channel Suspend */ + uint16_t :2; /*!< bit: 11..12 Reserved */ + uint16_t FERR:1; /*!< bit: 13 Fetch Error */ + uint16_t BUSY:1; /*!< bit: 14 Busy */ + uint16_t PEND:1; /*!< bit: 15 Pending */ + } bit; /*!< Structure used for bit access */ + uint16_t reg; /*!< Type used for register access */ +} DMAC_INTPEND_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define DMAC_INTPEND_OFFSET 0x20 /**< \brief (DMAC_INTPEND offset) Interrupt Pending */ +#define DMAC_INTPEND_RESETVALUE _U_(0x0000) /**< \brief (DMAC_INTPEND reset_value) Interrupt Pending */ + +#define DMAC_INTPEND_ID_Pos 0 /**< \brief (DMAC_INTPEND) Channel ID */ +#define DMAC_INTPEND_ID_Msk (_U_(0xF) << DMAC_INTPEND_ID_Pos) +#define DMAC_INTPEND_ID(value) (DMAC_INTPEND_ID_Msk & ((value) << DMAC_INTPEND_ID_Pos)) +#define DMAC_INTPEND_TERR_Pos 8 /**< \brief (DMAC_INTPEND) Transfer Error */ +#define DMAC_INTPEND_TERR (_U_(0x1) << DMAC_INTPEND_TERR_Pos) +#define DMAC_INTPEND_TCMPL_Pos 9 /**< \brief (DMAC_INTPEND) Transfer Complete */ +#define DMAC_INTPEND_TCMPL (_U_(0x1) << DMAC_INTPEND_TCMPL_Pos) +#define DMAC_INTPEND_SUSP_Pos 10 /**< \brief (DMAC_INTPEND) Channel Suspend */ +#define DMAC_INTPEND_SUSP (_U_(0x1) << DMAC_INTPEND_SUSP_Pos) +#define DMAC_INTPEND_FERR_Pos 13 /**< \brief (DMAC_INTPEND) Fetch Error */ +#define DMAC_INTPEND_FERR (_U_(0x1) << DMAC_INTPEND_FERR_Pos) +#define DMAC_INTPEND_BUSY_Pos 14 /**< \brief (DMAC_INTPEND) Busy */ +#define DMAC_INTPEND_BUSY (_U_(0x1) << DMAC_INTPEND_BUSY_Pos) +#define DMAC_INTPEND_PEND_Pos 15 /**< \brief (DMAC_INTPEND) Pending */ +#define DMAC_INTPEND_PEND (_U_(0x1) << DMAC_INTPEND_PEND_Pos) +#define DMAC_INTPEND_MASK _U_(0xE70F) /**< \brief (DMAC_INTPEND) MASK Register */ + +/* -------- DMAC_INTSTATUS : (DMAC Offset: 0x24) (R/ 32) Interrupt Status -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint32_t CHINT0:1; /*!< bit: 0 Channel 0 Pending Interrupt */ + uint32_t CHINT1:1; /*!< bit: 1 Channel 1 Pending Interrupt */ + uint32_t CHINT2:1; /*!< bit: 2 Channel 2 Pending Interrupt */ + uint32_t CHINT3:1; /*!< bit: 3 Channel 3 Pending Interrupt */ + uint32_t CHINT4:1; /*!< bit: 4 Channel 4 Pending Interrupt */ + uint32_t CHINT5:1; /*!< bit: 5 Channel 5 Pending Interrupt */ + uint32_t CHINT6:1; /*!< bit: 6 Channel 6 Pending Interrupt */ + uint32_t CHINT7:1; /*!< bit: 7 Channel 7 Pending Interrupt */ + uint32_t CHINT8:1; /*!< bit: 8 Channel 8 Pending Interrupt */ + uint32_t CHINT9:1; /*!< bit: 9 Channel 9 Pending Interrupt */ + uint32_t CHINT10:1; /*!< bit: 10 Channel 10 Pending Interrupt */ + uint32_t CHINT11:1; /*!< bit: 11 Channel 11 Pending Interrupt */ + uint32_t CHINT12:1; /*!< bit: 12 Channel 12 Pending Interrupt */ + uint32_t CHINT13:1; /*!< bit: 13 Channel 13 Pending Interrupt */ + uint32_t CHINT14:1; /*!< bit: 14 Channel 14 Pending Interrupt */ + uint32_t CHINT15:1; /*!< bit: 15 Channel 15 Pending Interrupt */ + uint32_t :16; /*!< bit: 16..31 Reserved */ + } bit; /*!< Structure used for bit access */ + struct { + uint32_t CHINT:16; /*!< bit: 0..15 Channel x Pending Interrupt */ + uint32_t :16; /*!< bit: 16..31 Reserved */ + } vec; /*!< Structure used for vec access */ + uint32_t reg; /*!< Type used for register access */ +} DMAC_INTSTATUS_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define DMAC_INTSTATUS_OFFSET 0x24 /**< \brief (DMAC_INTSTATUS offset) Interrupt Status */ +#define DMAC_INTSTATUS_RESETVALUE _U_(0x00000000) /**< \brief (DMAC_INTSTATUS reset_value) Interrupt Status */ + +#define DMAC_INTSTATUS_CHINT0_Pos 0 /**< \brief (DMAC_INTSTATUS) Channel 0 Pending Interrupt */ +#define DMAC_INTSTATUS_CHINT0 (_U_(1) << DMAC_INTSTATUS_CHINT0_Pos) +#define DMAC_INTSTATUS_CHINT1_Pos 1 /**< \brief (DMAC_INTSTATUS) Channel 1 Pending Interrupt */ +#define DMAC_INTSTATUS_CHINT1 (_U_(1) << DMAC_INTSTATUS_CHINT1_Pos) +#define DMAC_INTSTATUS_CHINT2_Pos 2 /**< \brief (DMAC_INTSTATUS) Channel 2 Pending Interrupt */ +#define DMAC_INTSTATUS_CHINT2 (_U_(1) << DMAC_INTSTATUS_CHINT2_Pos) +#define DMAC_INTSTATUS_CHINT3_Pos 3 /**< \brief (DMAC_INTSTATUS) Channel 3 Pending Interrupt */ +#define DMAC_INTSTATUS_CHINT3 (_U_(1) << DMAC_INTSTATUS_CHINT3_Pos) +#define DMAC_INTSTATUS_CHINT4_Pos 4 /**< \brief (DMAC_INTSTATUS) Channel 4 Pending Interrupt */ +#define DMAC_INTSTATUS_CHINT4 (_U_(1) << DMAC_INTSTATUS_CHINT4_Pos) +#define DMAC_INTSTATUS_CHINT5_Pos 5 /**< \brief (DMAC_INTSTATUS) Channel 5 Pending Interrupt */ +#define DMAC_INTSTATUS_CHINT5 (_U_(1) << DMAC_INTSTATUS_CHINT5_Pos) +#define DMAC_INTSTATUS_CHINT6_Pos 6 /**< \brief (DMAC_INTSTATUS) Channel 6 Pending Interrupt */ +#define DMAC_INTSTATUS_CHINT6 (_U_(1) << DMAC_INTSTATUS_CHINT6_Pos) +#define DMAC_INTSTATUS_CHINT7_Pos 7 /**< \brief (DMAC_INTSTATUS) Channel 7 Pending Interrupt */ +#define DMAC_INTSTATUS_CHINT7 (_U_(1) << DMAC_INTSTATUS_CHINT7_Pos) +#define DMAC_INTSTATUS_CHINT8_Pos 8 /**< \brief (DMAC_INTSTATUS) Channel 8 Pending Interrupt */ +#define DMAC_INTSTATUS_CHINT8 (_U_(1) << DMAC_INTSTATUS_CHINT8_Pos) +#define DMAC_INTSTATUS_CHINT9_Pos 9 /**< \brief (DMAC_INTSTATUS) Channel 9 Pending Interrupt */ +#define DMAC_INTSTATUS_CHINT9 (_U_(1) << DMAC_INTSTATUS_CHINT9_Pos) +#define DMAC_INTSTATUS_CHINT10_Pos 10 /**< \brief (DMAC_INTSTATUS) Channel 10 Pending Interrupt */ +#define DMAC_INTSTATUS_CHINT10 (_U_(1) << DMAC_INTSTATUS_CHINT10_Pos) +#define DMAC_INTSTATUS_CHINT11_Pos 11 /**< \brief (DMAC_INTSTATUS) Channel 11 Pending Interrupt */ +#define DMAC_INTSTATUS_CHINT11 (_U_(1) << DMAC_INTSTATUS_CHINT11_Pos) +#define DMAC_INTSTATUS_CHINT12_Pos 12 /**< \brief (DMAC_INTSTATUS) Channel 12 Pending Interrupt */ +#define DMAC_INTSTATUS_CHINT12 (_U_(1) << DMAC_INTSTATUS_CHINT12_Pos) +#define DMAC_INTSTATUS_CHINT13_Pos 13 /**< \brief (DMAC_INTSTATUS) Channel 13 Pending Interrupt */ +#define DMAC_INTSTATUS_CHINT13 (_U_(1) << DMAC_INTSTATUS_CHINT13_Pos) +#define DMAC_INTSTATUS_CHINT14_Pos 14 /**< \brief (DMAC_INTSTATUS) Channel 14 Pending Interrupt */ +#define DMAC_INTSTATUS_CHINT14 (_U_(1) << DMAC_INTSTATUS_CHINT14_Pos) +#define DMAC_INTSTATUS_CHINT15_Pos 15 /**< \brief (DMAC_INTSTATUS) Channel 15 Pending Interrupt */ +#define DMAC_INTSTATUS_CHINT15 (_U_(1) << DMAC_INTSTATUS_CHINT15_Pos) +#define DMAC_INTSTATUS_CHINT_Pos 0 /**< \brief (DMAC_INTSTATUS) Channel x Pending Interrupt */ +#define DMAC_INTSTATUS_CHINT_Msk (_U_(0xFFFF) << DMAC_INTSTATUS_CHINT_Pos) +#define DMAC_INTSTATUS_CHINT(value) (DMAC_INTSTATUS_CHINT_Msk & ((value) << DMAC_INTSTATUS_CHINT_Pos)) +#define DMAC_INTSTATUS_MASK _U_(0x0000FFFF) /**< \brief (DMAC_INTSTATUS) MASK Register */ + +/* -------- DMAC_BUSYCH : (DMAC Offset: 0x28) (R/ 32) Busy Channels -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint32_t BUSYCH0:1; /*!< bit: 0 Busy Channel 0 */ + uint32_t BUSYCH1:1; /*!< bit: 1 Busy Channel 1 */ + uint32_t BUSYCH2:1; /*!< bit: 2 Busy Channel 2 */ + uint32_t BUSYCH3:1; /*!< bit: 3 Busy Channel 3 */ + uint32_t BUSYCH4:1; /*!< bit: 4 Busy Channel 4 */ + uint32_t BUSYCH5:1; /*!< bit: 5 Busy Channel 5 */ + uint32_t BUSYCH6:1; /*!< bit: 6 Busy Channel 6 */ + uint32_t BUSYCH7:1; /*!< bit: 7 Busy Channel 7 */ + uint32_t BUSYCH8:1; /*!< bit: 8 Busy Channel 8 */ + uint32_t BUSYCH9:1; /*!< bit: 9 Busy Channel 9 */ + uint32_t BUSYCH10:1; /*!< bit: 10 Busy Channel 10 */ + uint32_t BUSYCH11:1; /*!< bit: 11 Busy Channel 11 */ + uint32_t BUSYCH12:1; /*!< bit: 12 Busy Channel 12 */ + uint32_t BUSYCH13:1; /*!< bit: 13 Busy Channel 13 */ + uint32_t BUSYCH14:1; /*!< bit: 14 Busy Channel 14 */ + uint32_t BUSYCH15:1; /*!< bit: 15 Busy Channel 15 */ + uint32_t :16; /*!< bit: 16..31 Reserved */ + } bit; /*!< Structure used for bit access */ + struct { + uint32_t BUSYCH:16; /*!< bit: 0..15 Busy Channel x */ + uint32_t :16; /*!< bit: 16..31 Reserved */ + } vec; /*!< Structure used for vec access */ + uint32_t reg; /*!< Type used for register access */ +} DMAC_BUSYCH_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define DMAC_BUSYCH_OFFSET 0x28 /**< \brief (DMAC_BUSYCH offset) Busy Channels */ +#define DMAC_BUSYCH_RESETVALUE _U_(0x00000000) /**< \brief (DMAC_BUSYCH reset_value) Busy Channels */ + +#define DMAC_BUSYCH_BUSYCH0_Pos 0 /**< \brief (DMAC_BUSYCH) Busy Channel 0 */ +#define DMAC_BUSYCH_BUSYCH0 (_U_(1) << DMAC_BUSYCH_BUSYCH0_Pos) +#define DMAC_BUSYCH_BUSYCH1_Pos 1 /**< \brief (DMAC_BUSYCH) Busy Channel 1 */ +#define DMAC_BUSYCH_BUSYCH1 (_U_(1) << DMAC_BUSYCH_BUSYCH1_Pos) +#define DMAC_BUSYCH_BUSYCH2_Pos 2 /**< \brief (DMAC_BUSYCH) Busy Channel 2 */ +#define DMAC_BUSYCH_BUSYCH2 (_U_(1) << DMAC_BUSYCH_BUSYCH2_Pos) +#define DMAC_BUSYCH_BUSYCH3_Pos 3 /**< \brief (DMAC_BUSYCH) Busy Channel 3 */ +#define DMAC_BUSYCH_BUSYCH3 (_U_(1) << DMAC_BUSYCH_BUSYCH3_Pos) +#define DMAC_BUSYCH_BUSYCH4_Pos 4 /**< \brief (DMAC_BUSYCH) Busy Channel 4 */ +#define DMAC_BUSYCH_BUSYCH4 (_U_(1) << DMAC_BUSYCH_BUSYCH4_Pos) +#define DMAC_BUSYCH_BUSYCH5_Pos 5 /**< \brief (DMAC_BUSYCH) Busy Channel 5 */ +#define DMAC_BUSYCH_BUSYCH5 (_U_(1) << DMAC_BUSYCH_BUSYCH5_Pos) +#define DMAC_BUSYCH_BUSYCH6_Pos 6 /**< \brief (DMAC_BUSYCH) Busy Channel 6 */ +#define DMAC_BUSYCH_BUSYCH6 (_U_(1) << DMAC_BUSYCH_BUSYCH6_Pos) +#define DMAC_BUSYCH_BUSYCH7_Pos 7 /**< \brief (DMAC_BUSYCH) Busy Channel 7 */ +#define DMAC_BUSYCH_BUSYCH7 (_U_(1) << DMAC_BUSYCH_BUSYCH7_Pos) +#define DMAC_BUSYCH_BUSYCH8_Pos 8 /**< \brief (DMAC_BUSYCH) Busy Channel 8 */ +#define DMAC_BUSYCH_BUSYCH8 (_U_(1) << DMAC_BUSYCH_BUSYCH8_Pos) +#define DMAC_BUSYCH_BUSYCH9_Pos 9 /**< \brief (DMAC_BUSYCH) Busy Channel 9 */ +#define DMAC_BUSYCH_BUSYCH9 (_U_(1) << DMAC_BUSYCH_BUSYCH9_Pos) +#define DMAC_BUSYCH_BUSYCH10_Pos 10 /**< \brief (DMAC_BUSYCH) Busy Channel 10 */ +#define DMAC_BUSYCH_BUSYCH10 (_U_(1) << DMAC_BUSYCH_BUSYCH10_Pos) +#define DMAC_BUSYCH_BUSYCH11_Pos 11 /**< \brief (DMAC_BUSYCH) Busy Channel 11 */ +#define DMAC_BUSYCH_BUSYCH11 (_U_(1) << DMAC_BUSYCH_BUSYCH11_Pos) +#define DMAC_BUSYCH_BUSYCH12_Pos 12 /**< \brief (DMAC_BUSYCH) Busy Channel 12 */ +#define DMAC_BUSYCH_BUSYCH12 (_U_(1) << DMAC_BUSYCH_BUSYCH12_Pos) +#define DMAC_BUSYCH_BUSYCH13_Pos 13 /**< \brief (DMAC_BUSYCH) Busy Channel 13 */ +#define DMAC_BUSYCH_BUSYCH13 (_U_(1) << DMAC_BUSYCH_BUSYCH13_Pos) +#define DMAC_BUSYCH_BUSYCH14_Pos 14 /**< \brief (DMAC_BUSYCH) Busy Channel 14 */ +#define DMAC_BUSYCH_BUSYCH14 (_U_(1) << DMAC_BUSYCH_BUSYCH14_Pos) +#define DMAC_BUSYCH_BUSYCH15_Pos 15 /**< \brief (DMAC_BUSYCH) Busy Channel 15 */ +#define DMAC_BUSYCH_BUSYCH15 (_U_(1) << DMAC_BUSYCH_BUSYCH15_Pos) +#define DMAC_BUSYCH_BUSYCH_Pos 0 /**< \brief (DMAC_BUSYCH) Busy Channel x */ +#define DMAC_BUSYCH_BUSYCH_Msk (_U_(0xFFFF) << DMAC_BUSYCH_BUSYCH_Pos) +#define DMAC_BUSYCH_BUSYCH(value) (DMAC_BUSYCH_BUSYCH_Msk & ((value) << DMAC_BUSYCH_BUSYCH_Pos)) +#define DMAC_BUSYCH_MASK _U_(0x0000FFFF) /**< \brief (DMAC_BUSYCH) MASK Register */ + +/* -------- DMAC_PENDCH : (DMAC Offset: 0x2C) (R/ 32) Pending Channels -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint32_t PENDCH0:1; /*!< bit: 0 Pending Channel 0 */ + uint32_t PENDCH1:1; /*!< bit: 1 Pending Channel 1 */ + uint32_t PENDCH2:1; /*!< bit: 2 Pending Channel 2 */ + uint32_t PENDCH3:1; /*!< bit: 3 Pending Channel 3 */ + uint32_t PENDCH4:1; /*!< bit: 4 Pending Channel 4 */ + uint32_t PENDCH5:1; /*!< bit: 5 Pending Channel 5 */ + uint32_t PENDCH6:1; /*!< bit: 6 Pending Channel 6 */ + uint32_t PENDCH7:1; /*!< bit: 7 Pending Channel 7 */ + uint32_t PENDCH8:1; /*!< bit: 8 Pending Channel 8 */ + uint32_t PENDCH9:1; /*!< bit: 9 Pending Channel 9 */ + uint32_t PENDCH10:1; /*!< bit: 10 Pending Channel 10 */ + uint32_t PENDCH11:1; /*!< bit: 11 Pending Channel 11 */ + uint32_t PENDCH12:1; /*!< bit: 12 Pending Channel 12 */ + uint32_t PENDCH13:1; /*!< bit: 13 Pending Channel 13 */ + uint32_t PENDCH14:1; /*!< bit: 14 Pending Channel 14 */ + uint32_t PENDCH15:1; /*!< bit: 15 Pending Channel 15 */ + uint32_t :16; /*!< bit: 16..31 Reserved */ + } bit; /*!< Structure used for bit access */ + struct { + uint32_t PENDCH:16; /*!< bit: 0..15 Pending Channel x */ + uint32_t :16; /*!< bit: 16..31 Reserved */ + } vec; /*!< Structure used for vec access */ + uint32_t reg; /*!< Type used for register access */ +} DMAC_PENDCH_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define DMAC_PENDCH_OFFSET 0x2C /**< \brief (DMAC_PENDCH offset) Pending Channels */ +#define DMAC_PENDCH_RESETVALUE _U_(0x00000000) /**< \brief (DMAC_PENDCH reset_value) Pending Channels */ + +#define DMAC_PENDCH_PENDCH0_Pos 0 /**< \brief (DMAC_PENDCH) Pending Channel 0 */ +#define DMAC_PENDCH_PENDCH0 (_U_(1) << DMAC_PENDCH_PENDCH0_Pos) +#define DMAC_PENDCH_PENDCH1_Pos 1 /**< \brief (DMAC_PENDCH) Pending Channel 1 */ +#define DMAC_PENDCH_PENDCH1 (_U_(1) << DMAC_PENDCH_PENDCH1_Pos) +#define DMAC_PENDCH_PENDCH2_Pos 2 /**< \brief (DMAC_PENDCH) Pending Channel 2 */ +#define DMAC_PENDCH_PENDCH2 (_U_(1) << DMAC_PENDCH_PENDCH2_Pos) +#define DMAC_PENDCH_PENDCH3_Pos 3 /**< \brief (DMAC_PENDCH) Pending Channel 3 */ +#define DMAC_PENDCH_PENDCH3 (_U_(1) << DMAC_PENDCH_PENDCH3_Pos) +#define DMAC_PENDCH_PENDCH4_Pos 4 /**< \brief (DMAC_PENDCH) Pending Channel 4 */ +#define DMAC_PENDCH_PENDCH4 (_U_(1) << DMAC_PENDCH_PENDCH4_Pos) +#define DMAC_PENDCH_PENDCH5_Pos 5 /**< \brief (DMAC_PENDCH) Pending Channel 5 */ +#define DMAC_PENDCH_PENDCH5 (_U_(1) << DMAC_PENDCH_PENDCH5_Pos) +#define DMAC_PENDCH_PENDCH6_Pos 6 /**< \brief (DMAC_PENDCH) Pending Channel 6 */ +#define DMAC_PENDCH_PENDCH6 (_U_(1) << DMAC_PENDCH_PENDCH6_Pos) +#define DMAC_PENDCH_PENDCH7_Pos 7 /**< \brief (DMAC_PENDCH) Pending Channel 7 */ +#define DMAC_PENDCH_PENDCH7 (_U_(1) << DMAC_PENDCH_PENDCH7_Pos) +#define DMAC_PENDCH_PENDCH8_Pos 8 /**< \brief (DMAC_PENDCH) Pending Channel 8 */ +#define DMAC_PENDCH_PENDCH8 (_U_(1) << DMAC_PENDCH_PENDCH8_Pos) +#define DMAC_PENDCH_PENDCH9_Pos 9 /**< \brief (DMAC_PENDCH) Pending Channel 9 */ +#define DMAC_PENDCH_PENDCH9 (_U_(1) << DMAC_PENDCH_PENDCH9_Pos) +#define DMAC_PENDCH_PENDCH10_Pos 10 /**< \brief (DMAC_PENDCH) Pending Channel 10 */ +#define DMAC_PENDCH_PENDCH10 (_U_(1) << DMAC_PENDCH_PENDCH10_Pos) +#define DMAC_PENDCH_PENDCH11_Pos 11 /**< \brief (DMAC_PENDCH) Pending Channel 11 */ +#define DMAC_PENDCH_PENDCH11 (_U_(1) << DMAC_PENDCH_PENDCH11_Pos) +#define DMAC_PENDCH_PENDCH12_Pos 12 /**< \brief (DMAC_PENDCH) Pending Channel 12 */ +#define DMAC_PENDCH_PENDCH12 (_U_(1) << DMAC_PENDCH_PENDCH12_Pos) +#define DMAC_PENDCH_PENDCH13_Pos 13 /**< \brief (DMAC_PENDCH) Pending Channel 13 */ +#define DMAC_PENDCH_PENDCH13 (_U_(1) << DMAC_PENDCH_PENDCH13_Pos) +#define DMAC_PENDCH_PENDCH14_Pos 14 /**< \brief (DMAC_PENDCH) Pending Channel 14 */ +#define DMAC_PENDCH_PENDCH14 (_U_(1) << DMAC_PENDCH_PENDCH14_Pos) +#define DMAC_PENDCH_PENDCH15_Pos 15 /**< \brief (DMAC_PENDCH) Pending Channel 15 */ +#define DMAC_PENDCH_PENDCH15 (_U_(1) << DMAC_PENDCH_PENDCH15_Pos) +#define DMAC_PENDCH_PENDCH_Pos 0 /**< \brief (DMAC_PENDCH) Pending Channel x */ +#define DMAC_PENDCH_PENDCH_Msk (_U_(0xFFFF) << DMAC_PENDCH_PENDCH_Pos) +#define DMAC_PENDCH_PENDCH(value) (DMAC_PENDCH_PENDCH_Msk & ((value) << DMAC_PENDCH_PENDCH_Pos)) +#define DMAC_PENDCH_MASK _U_(0x0000FFFF) /**< \brief (DMAC_PENDCH) MASK Register */ + +/* -------- DMAC_ACTIVE : (DMAC Offset: 0x30) (R/ 32) Active Channel and Levels -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint32_t LVLEX0:1; /*!< bit: 0 Level 0 Channel Trigger Request Executing */ + uint32_t LVLEX1:1; /*!< bit: 1 Level 1 Channel Trigger Request Executing */ + uint32_t LVLEX2:1; /*!< bit: 2 Level 2 Channel Trigger Request Executing */ + uint32_t LVLEX3:1; /*!< bit: 3 Level 3 Channel Trigger Request Executing */ + uint32_t :4; /*!< bit: 4.. 7 Reserved */ + uint32_t ID:5; /*!< bit: 8..12 Active Channel ID */ + uint32_t :2; /*!< bit: 13..14 Reserved */ + uint32_t ABUSY:1; /*!< bit: 15 Active Channel Busy */ + uint32_t BTCNT:16; /*!< bit: 16..31 Active Channel Block Transfer Count */ + } bit; /*!< Structure used for bit access */ + struct { + uint32_t LVLEX:4; /*!< bit: 0.. 3 Level x Channel Trigger Request Executing */ + uint32_t :28; /*!< bit: 4..31 Reserved */ + } vec; /*!< Structure used for vec access */ + uint32_t reg; /*!< Type used for register access */ +} DMAC_ACTIVE_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define DMAC_ACTIVE_OFFSET 0x30 /**< \brief (DMAC_ACTIVE offset) Active Channel and Levels */ +#define DMAC_ACTIVE_RESETVALUE _U_(0x00000000) /**< \brief (DMAC_ACTIVE reset_value) Active Channel and Levels */ + +#define DMAC_ACTIVE_LVLEX0_Pos 0 /**< \brief (DMAC_ACTIVE) Level 0 Channel Trigger Request Executing */ +#define DMAC_ACTIVE_LVLEX0 (_U_(1) << DMAC_ACTIVE_LVLEX0_Pos) +#define DMAC_ACTIVE_LVLEX1_Pos 1 /**< \brief (DMAC_ACTIVE) Level 1 Channel Trigger Request Executing */ +#define DMAC_ACTIVE_LVLEX1 (_U_(1) << DMAC_ACTIVE_LVLEX1_Pos) +#define DMAC_ACTIVE_LVLEX2_Pos 2 /**< \brief (DMAC_ACTIVE) Level 2 Channel Trigger Request Executing */ +#define DMAC_ACTIVE_LVLEX2 (_U_(1) << DMAC_ACTIVE_LVLEX2_Pos) +#define DMAC_ACTIVE_LVLEX3_Pos 3 /**< \brief (DMAC_ACTIVE) Level 3 Channel Trigger Request Executing */ +#define DMAC_ACTIVE_LVLEX3 (_U_(1) << DMAC_ACTIVE_LVLEX3_Pos) +#define DMAC_ACTIVE_LVLEX_Pos 0 /**< \brief (DMAC_ACTIVE) Level x Channel Trigger Request Executing */ +#define DMAC_ACTIVE_LVLEX_Msk (_U_(0xF) << DMAC_ACTIVE_LVLEX_Pos) +#define DMAC_ACTIVE_LVLEX(value) (DMAC_ACTIVE_LVLEX_Msk & ((value) << DMAC_ACTIVE_LVLEX_Pos)) +#define DMAC_ACTIVE_ID_Pos 8 /**< \brief (DMAC_ACTIVE) Active Channel ID */ +#define DMAC_ACTIVE_ID_Msk (_U_(0x1F) << DMAC_ACTIVE_ID_Pos) +#define DMAC_ACTIVE_ID(value) (DMAC_ACTIVE_ID_Msk & ((value) << DMAC_ACTIVE_ID_Pos)) +#define DMAC_ACTIVE_ABUSY_Pos 15 /**< \brief (DMAC_ACTIVE) Active Channel Busy */ +#define DMAC_ACTIVE_ABUSY (_U_(0x1) << DMAC_ACTIVE_ABUSY_Pos) +#define DMAC_ACTIVE_BTCNT_Pos 16 /**< \brief (DMAC_ACTIVE) Active Channel Block Transfer Count */ +#define DMAC_ACTIVE_BTCNT_Msk (_U_(0xFFFF) << DMAC_ACTIVE_BTCNT_Pos) +#define DMAC_ACTIVE_BTCNT(value) (DMAC_ACTIVE_BTCNT_Msk & ((value) << DMAC_ACTIVE_BTCNT_Pos)) +#define DMAC_ACTIVE_MASK _U_(0xFFFF9F0F) /**< \brief (DMAC_ACTIVE) MASK Register */ + +/* -------- DMAC_BASEADDR : (DMAC Offset: 0x34) (R/W 32) Descriptor Memory Section Base Address -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint32_t BASEADDR:32; /*!< bit: 0..31 Descriptor Memory Base Address */ + } bit; /*!< Structure used for bit access */ + uint32_t reg; /*!< Type used for register access */ +} DMAC_BASEADDR_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define DMAC_BASEADDR_OFFSET 0x34 /**< \brief (DMAC_BASEADDR offset) Descriptor Memory Section Base Address */ +#define DMAC_BASEADDR_RESETVALUE _U_(0x00000000) /**< \brief (DMAC_BASEADDR reset_value) Descriptor Memory Section Base Address */ + +#define DMAC_BASEADDR_BASEADDR_Pos 0 /**< \brief (DMAC_BASEADDR) Descriptor Memory Base Address */ +#define DMAC_BASEADDR_BASEADDR_Msk (_U_(0xFFFFFFFF) << DMAC_BASEADDR_BASEADDR_Pos) +#define DMAC_BASEADDR_BASEADDR(value) (DMAC_BASEADDR_BASEADDR_Msk & ((value) << DMAC_BASEADDR_BASEADDR_Pos)) +#define DMAC_BASEADDR_MASK _U_(0xFFFFFFFF) /**< \brief (DMAC_BASEADDR) MASK Register */ + +/* -------- DMAC_WRBADDR : (DMAC Offset: 0x38) (R/W 32) Write-Back Memory Section Base Address -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint32_t WRBADDR:32; /*!< bit: 0..31 Write-Back Memory Base Address */ + } bit; /*!< Structure used for bit access */ + uint32_t reg; /*!< Type used for register access */ +} DMAC_WRBADDR_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define DMAC_WRBADDR_OFFSET 0x38 /**< \brief (DMAC_WRBADDR offset) Write-Back Memory Section Base Address */ +#define DMAC_WRBADDR_RESETVALUE _U_(0x00000000) /**< \brief (DMAC_WRBADDR reset_value) Write-Back Memory Section Base Address */ + +#define DMAC_WRBADDR_WRBADDR_Pos 0 /**< \brief (DMAC_WRBADDR) Write-Back Memory Base Address */ +#define DMAC_WRBADDR_WRBADDR_Msk (_U_(0xFFFFFFFF) << DMAC_WRBADDR_WRBADDR_Pos) +#define DMAC_WRBADDR_WRBADDR(value) (DMAC_WRBADDR_WRBADDR_Msk & ((value) << DMAC_WRBADDR_WRBADDR_Pos)) +#define DMAC_WRBADDR_MASK _U_(0xFFFFFFFF) /**< \brief (DMAC_WRBADDR) MASK Register */ + +/* -------- DMAC_CHID : (DMAC Offset: 0x3F) (R/W 8) Channel ID -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t ID:4; /*!< bit: 0.. 3 Channel ID */ + uint8_t :4; /*!< bit: 4.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + uint8_t reg; /*!< Type used for register access */ +} DMAC_CHID_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define DMAC_CHID_OFFSET 0x3F /**< \brief (DMAC_CHID offset) Channel ID */ +#define DMAC_CHID_RESETVALUE _U_(0x00) /**< \brief (DMAC_CHID reset_value) Channel ID */ + +#define DMAC_CHID_ID_Pos 0 /**< \brief (DMAC_CHID) Channel ID */ +#define DMAC_CHID_ID_Msk (_U_(0xF) << DMAC_CHID_ID_Pos) +#define DMAC_CHID_ID(value) (DMAC_CHID_ID_Msk & ((value) << DMAC_CHID_ID_Pos)) +#define DMAC_CHID_MASK _U_(0x0F) /**< \brief (DMAC_CHID) MASK Register */ + +/* -------- DMAC_CHCTRLA : (DMAC Offset: 0x40) (R/W 8) Channel Control A -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t SWRST:1; /*!< bit: 0 Channel Software Reset */ + uint8_t ENABLE:1; /*!< bit: 1 Channel Enable */ + uint8_t :4; /*!< bit: 2.. 5 Reserved */ + uint8_t RUNSTDBY:1; /*!< bit: 6 Channel run in standby */ + uint8_t :1; /*!< bit: 7 Reserved */ + } bit; /*!< Structure used for bit access */ + uint8_t reg; /*!< Type used for register access */ +} DMAC_CHCTRLA_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define DMAC_CHCTRLA_OFFSET 0x40 /**< \brief (DMAC_CHCTRLA offset) Channel Control A */ +#define DMAC_CHCTRLA_RESETVALUE _U_(0x00) /**< \brief (DMAC_CHCTRLA reset_value) Channel Control A */ + +#define DMAC_CHCTRLA_SWRST_Pos 0 /**< \brief (DMAC_CHCTRLA) Channel Software Reset */ +#define DMAC_CHCTRLA_SWRST (_U_(0x1) << DMAC_CHCTRLA_SWRST_Pos) +#define DMAC_CHCTRLA_ENABLE_Pos 1 /**< \brief (DMAC_CHCTRLA) Channel Enable */ +#define DMAC_CHCTRLA_ENABLE (_U_(0x1) << DMAC_CHCTRLA_ENABLE_Pos) +#define DMAC_CHCTRLA_RUNSTDBY_Pos 6 /**< \brief (DMAC_CHCTRLA) Channel run in standby */ +#define DMAC_CHCTRLA_RUNSTDBY (_U_(0x1) << DMAC_CHCTRLA_RUNSTDBY_Pos) +#define DMAC_CHCTRLA_MASK _U_(0x43) /**< \brief (DMAC_CHCTRLA) MASK Register */ + +/* -------- DMAC_CHCTRLB : (DMAC Offset: 0x44) (R/W 32) Channel Control B -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint32_t EVACT:3; /*!< bit: 0.. 2 Event Input Action */ + uint32_t EVIE:1; /*!< bit: 3 Channel Event Input Enable */ + uint32_t EVOE:1; /*!< bit: 4 Channel Event Output Enable */ + uint32_t LVL:2; /*!< bit: 5.. 6 Channel Arbitration Level */ + uint32_t :1; /*!< bit: 7 Reserved */ + uint32_t TRIGSRC:6; /*!< bit: 8..13 Trigger Source */ + uint32_t :8; /*!< bit: 14..21 Reserved */ + uint32_t TRIGACT:2; /*!< bit: 22..23 Trigger Action */ + uint32_t CMD:2; /*!< bit: 24..25 Software Command */ + uint32_t :6; /*!< bit: 26..31 Reserved */ + } bit; /*!< Structure used for bit access */ + uint32_t reg; /*!< Type used for register access */ +} DMAC_CHCTRLB_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define DMAC_CHCTRLB_OFFSET 0x44 /**< \brief (DMAC_CHCTRLB offset) Channel Control B */ +#define DMAC_CHCTRLB_RESETVALUE _U_(0x00000000) /**< \brief (DMAC_CHCTRLB reset_value) Channel Control B */ + +#define DMAC_CHCTRLB_EVACT_Pos 0 /**< \brief (DMAC_CHCTRLB) Event Input Action */ +#define DMAC_CHCTRLB_EVACT_Msk (_U_(0x7) << DMAC_CHCTRLB_EVACT_Pos) +#define DMAC_CHCTRLB_EVACT(value) (DMAC_CHCTRLB_EVACT_Msk & ((value) << DMAC_CHCTRLB_EVACT_Pos)) +#define DMAC_CHCTRLB_EVACT_NOACT_Val _U_(0x0) /**< \brief (DMAC_CHCTRLB) No action */ +#define DMAC_CHCTRLB_EVACT_TRIG_Val _U_(0x1) /**< \brief (DMAC_CHCTRLB) Transfer and periodic transfer trigger */ +#define DMAC_CHCTRLB_EVACT_CTRIG_Val _U_(0x2) /**< \brief (DMAC_CHCTRLB) Conditional transfer trigger */ +#define DMAC_CHCTRLB_EVACT_CBLOCK_Val _U_(0x3) /**< \brief (DMAC_CHCTRLB) Conditional block transfer */ +#define DMAC_CHCTRLB_EVACT_SUSPEND_Val _U_(0x4) /**< \brief (DMAC_CHCTRLB) Channel suspend operation */ +#define DMAC_CHCTRLB_EVACT_RESUME_Val _U_(0x5) /**< \brief (DMAC_CHCTRLB) Channel resume operation */ +#define DMAC_CHCTRLB_EVACT_SSKIP_Val _U_(0x6) /**< \brief (DMAC_CHCTRLB) Skip next block suspend action */ +#define DMAC_CHCTRLB_EVACT_NOACT (DMAC_CHCTRLB_EVACT_NOACT_Val << DMAC_CHCTRLB_EVACT_Pos) +#define DMAC_CHCTRLB_EVACT_TRIG (DMAC_CHCTRLB_EVACT_TRIG_Val << DMAC_CHCTRLB_EVACT_Pos) +#define DMAC_CHCTRLB_EVACT_CTRIG (DMAC_CHCTRLB_EVACT_CTRIG_Val << DMAC_CHCTRLB_EVACT_Pos) +#define DMAC_CHCTRLB_EVACT_CBLOCK (DMAC_CHCTRLB_EVACT_CBLOCK_Val << DMAC_CHCTRLB_EVACT_Pos) +#define DMAC_CHCTRLB_EVACT_SUSPEND (DMAC_CHCTRLB_EVACT_SUSPEND_Val << DMAC_CHCTRLB_EVACT_Pos) +#define DMAC_CHCTRLB_EVACT_RESUME (DMAC_CHCTRLB_EVACT_RESUME_Val << DMAC_CHCTRLB_EVACT_Pos) +#define DMAC_CHCTRLB_EVACT_SSKIP (DMAC_CHCTRLB_EVACT_SSKIP_Val << DMAC_CHCTRLB_EVACT_Pos) +#define DMAC_CHCTRLB_EVIE_Pos 3 /**< \brief (DMAC_CHCTRLB) Channel Event Input Enable */ +#define DMAC_CHCTRLB_EVIE (_U_(0x1) << DMAC_CHCTRLB_EVIE_Pos) +#define DMAC_CHCTRLB_EVOE_Pos 4 /**< \brief (DMAC_CHCTRLB) Channel Event Output Enable */ +#define DMAC_CHCTRLB_EVOE (_U_(0x1) << DMAC_CHCTRLB_EVOE_Pos) +#define DMAC_CHCTRLB_LVL_Pos 5 /**< \brief (DMAC_CHCTRLB) Channel Arbitration Level */ +#define DMAC_CHCTRLB_LVL_Msk (_U_(0x3) << DMAC_CHCTRLB_LVL_Pos) +#define DMAC_CHCTRLB_LVL(value) (DMAC_CHCTRLB_LVL_Msk & ((value) << DMAC_CHCTRLB_LVL_Pos)) +#define DMAC_CHCTRLB_TRIGSRC_Pos 8 /**< \brief (DMAC_CHCTRLB) Trigger Source */ +#define DMAC_CHCTRLB_TRIGSRC_Msk (_U_(0x3F) << DMAC_CHCTRLB_TRIGSRC_Pos) +#define DMAC_CHCTRLB_TRIGSRC(value) (DMAC_CHCTRLB_TRIGSRC_Msk & ((value) << DMAC_CHCTRLB_TRIGSRC_Pos)) +#define DMAC_CHCTRLB_TRIGSRC_DISABLE_Val _U_(0x0) /**< \brief (DMAC_CHCTRLB) Only software/event triggers */ +#define DMAC_CHCTRLB_TRIGSRC_DISABLE (DMAC_CHCTRLB_TRIGSRC_DISABLE_Val << DMAC_CHCTRLB_TRIGSRC_Pos) +#define DMAC_CHCTRLB_TRIGACT_Pos 22 /**< \brief (DMAC_CHCTRLB) Trigger Action */ +#define DMAC_CHCTRLB_TRIGACT_Msk (_U_(0x3) << DMAC_CHCTRLB_TRIGACT_Pos) +#define DMAC_CHCTRLB_TRIGACT(value) (DMAC_CHCTRLB_TRIGACT_Msk & ((value) << DMAC_CHCTRLB_TRIGACT_Pos)) +#define DMAC_CHCTRLB_TRIGACT_BLOCK_Val _U_(0x0) /**< \brief (DMAC_CHCTRLB) One trigger required for each block transfer */ +#define DMAC_CHCTRLB_TRIGACT_BEAT_Val _U_(0x2) /**< \brief (DMAC_CHCTRLB) One trigger required for each beat transfer */ +#define DMAC_CHCTRLB_TRIGACT_TRANSACTION_Val _U_(0x3) /**< \brief (DMAC_CHCTRLB) One trigger required for each transaction */ +#define DMAC_CHCTRLB_TRIGACT_BLOCK (DMAC_CHCTRLB_TRIGACT_BLOCK_Val << DMAC_CHCTRLB_TRIGACT_Pos) +#define DMAC_CHCTRLB_TRIGACT_BEAT (DMAC_CHCTRLB_TRIGACT_BEAT_Val << DMAC_CHCTRLB_TRIGACT_Pos) +#define DMAC_CHCTRLB_TRIGACT_TRANSACTION (DMAC_CHCTRLB_TRIGACT_TRANSACTION_Val << DMAC_CHCTRLB_TRIGACT_Pos) +#define DMAC_CHCTRLB_CMD_Pos 24 /**< \brief (DMAC_CHCTRLB) Software Command */ +#define DMAC_CHCTRLB_CMD_Msk (_U_(0x3) << DMAC_CHCTRLB_CMD_Pos) +#define DMAC_CHCTRLB_CMD(value) (DMAC_CHCTRLB_CMD_Msk & ((value) << DMAC_CHCTRLB_CMD_Pos)) +#define DMAC_CHCTRLB_CMD_NOACT_Val _U_(0x0) /**< \brief (DMAC_CHCTRLB) No action */ +#define DMAC_CHCTRLB_CMD_SUSPEND_Val _U_(0x1) /**< \brief (DMAC_CHCTRLB) Channel suspend operation */ +#define DMAC_CHCTRLB_CMD_RESUME_Val _U_(0x2) /**< \brief (DMAC_CHCTRLB) Channel resume operation */ +#define DMAC_CHCTRLB_CMD_NOACT (DMAC_CHCTRLB_CMD_NOACT_Val << DMAC_CHCTRLB_CMD_Pos) +#define DMAC_CHCTRLB_CMD_SUSPEND (DMAC_CHCTRLB_CMD_SUSPEND_Val << DMAC_CHCTRLB_CMD_Pos) +#define DMAC_CHCTRLB_CMD_RESUME (DMAC_CHCTRLB_CMD_RESUME_Val << DMAC_CHCTRLB_CMD_Pos) +#define DMAC_CHCTRLB_MASK _U_(0x03C03F7F) /**< \brief (DMAC_CHCTRLB) MASK Register */ + +/* -------- DMAC_CHINTENCLR : (DMAC Offset: 0x4C) (R/W 8) Channel Interrupt Enable Clear -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t TERR:1; /*!< bit: 0 Channel Transfer Error Interrupt Enable */ + uint8_t TCMPL:1; /*!< bit: 1 Channel Transfer Complete Interrupt Enable */ + uint8_t SUSP:1; /*!< bit: 2 Channel Suspend Interrupt Enable */ + uint8_t :5; /*!< bit: 3.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + uint8_t reg; /*!< Type used for register access */ +} DMAC_CHINTENCLR_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define DMAC_CHINTENCLR_OFFSET 0x4C /**< \brief (DMAC_CHINTENCLR offset) Channel Interrupt Enable Clear */ +#define DMAC_CHINTENCLR_RESETVALUE _U_(0x00) /**< \brief (DMAC_CHINTENCLR reset_value) Channel Interrupt Enable Clear */ + +#define DMAC_CHINTENCLR_TERR_Pos 0 /**< \brief (DMAC_CHINTENCLR) Channel Transfer Error Interrupt Enable */ +#define DMAC_CHINTENCLR_TERR (_U_(0x1) << DMAC_CHINTENCLR_TERR_Pos) +#define DMAC_CHINTENCLR_TCMPL_Pos 1 /**< \brief (DMAC_CHINTENCLR) Channel Transfer Complete Interrupt Enable */ +#define DMAC_CHINTENCLR_TCMPL (_U_(0x1) << DMAC_CHINTENCLR_TCMPL_Pos) +#define DMAC_CHINTENCLR_SUSP_Pos 2 /**< \brief (DMAC_CHINTENCLR) Channel Suspend Interrupt Enable */ +#define DMAC_CHINTENCLR_SUSP (_U_(0x1) << DMAC_CHINTENCLR_SUSP_Pos) +#define DMAC_CHINTENCLR_MASK _U_(0x07) /**< \brief (DMAC_CHINTENCLR) MASK Register */ + +/* -------- DMAC_CHINTENSET : (DMAC Offset: 0x4D) (R/W 8) Channel Interrupt Enable Set -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t TERR:1; /*!< bit: 0 Channel Transfer Error Interrupt Enable */ + uint8_t TCMPL:1; /*!< bit: 1 Channel Transfer Complete Interrupt Enable */ + uint8_t SUSP:1; /*!< bit: 2 Channel Suspend Interrupt Enable */ + uint8_t :5; /*!< bit: 3.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + uint8_t reg; /*!< Type used for register access */ +} DMAC_CHINTENSET_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define DMAC_CHINTENSET_OFFSET 0x4D /**< \brief (DMAC_CHINTENSET offset) Channel Interrupt Enable Set */ +#define DMAC_CHINTENSET_RESETVALUE _U_(0x00) /**< \brief (DMAC_CHINTENSET reset_value) Channel Interrupt Enable Set */ + +#define DMAC_CHINTENSET_TERR_Pos 0 /**< \brief (DMAC_CHINTENSET) Channel Transfer Error Interrupt Enable */ +#define DMAC_CHINTENSET_TERR (_U_(0x1) << DMAC_CHINTENSET_TERR_Pos) +#define DMAC_CHINTENSET_TCMPL_Pos 1 /**< \brief (DMAC_CHINTENSET) Channel Transfer Complete Interrupt Enable */ +#define DMAC_CHINTENSET_TCMPL (_U_(0x1) << DMAC_CHINTENSET_TCMPL_Pos) +#define DMAC_CHINTENSET_SUSP_Pos 2 /**< \brief (DMAC_CHINTENSET) Channel Suspend Interrupt Enable */ +#define DMAC_CHINTENSET_SUSP (_U_(0x1) << DMAC_CHINTENSET_SUSP_Pos) +#define DMAC_CHINTENSET_MASK _U_(0x07) /**< \brief (DMAC_CHINTENSET) MASK Register */ + +/* -------- DMAC_CHINTFLAG : (DMAC Offset: 0x4E) (R/W 8) Channel Interrupt Flag Status and Clear -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { // __I to avoid read-modify-write on write-to-clear register + struct { + __I uint8_t TERR:1; /*!< bit: 0 Channel Transfer Error */ + __I uint8_t TCMPL:1; /*!< bit: 1 Channel Transfer Complete */ + __I uint8_t SUSP:1; /*!< bit: 2 Channel Suspend */ + __I uint8_t :5; /*!< bit: 3.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + uint8_t reg; /*!< Type used for register access */ +} DMAC_CHINTFLAG_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define DMAC_CHINTFLAG_OFFSET 0x4E /**< \brief (DMAC_CHINTFLAG offset) Channel Interrupt Flag Status and Clear */ +#define DMAC_CHINTFLAG_RESETVALUE _U_(0x00) /**< \brief (DMAC_CHINTFLAG reset_value) Channel Interrupt Flag Status and Clear */ + +#define DMAC_CHINTFLAG_TERR_Pos 0 /**< \brief (DMAC_CHINTFLAG) Channel Transfer Error */ +#define DMAC_CHINTFLAG_TERR (_U_(0x1) << DMAC_CHINTFLAG_TERR_Pos) +#define DMAC_CHINTFLAG_TCMPL_Pos 1 /**< \brief (DMAC_CHINTFLAG) Channel Transfer Complete */ +#define DMAC_CHINTFLAG_TCMPL (_U_(0x1) << DMAC_CHINTFLAG_TCMPL_Pos) +#define DMAC_CHINTFLAG_SUSP_Pos 2 /**< \brief (DMAC_CHINTFLAG) Channel Suspend */ +#define DMAC_CHINTFLAG_SUSP (_U_(0x1) << DMAC_CHINTFLAG_SUSP_Pos) +#define DMAC_CHINTFLAG_MASK _U_(0x07) /**< \brief (DMAC_CHINTFLAG) MASK Register */ + +/* -------- DMAC_CHSTATUS : (DMAC Offset: 0x4F) (R/ 8) Channel Status -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint8_t PEND:1; /*!< bit: 0 Channel Pending */ + uint8_t BUSY:1; /*!< bit: 1 Channel Busy */ + uint8_t FERR:1; /*!< bit: 2 Channel Fetch Error */ + uint8_t :5; /*!< bit: 3.. 7 Reserved */ + } bit; /*!< Structure used for bit access */ + uint8_t reg; /*!< Type used for register access */ +} DMAC_CHSTATUS_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define DMAC_CHSTATUS_OFFSET 0x4F /**< \brief (DMAC_CHSTATUS offset) Channel Status */ +#define DMAC_CHSTATUS_RESETVALUE _U_(0x00) /**< \brief (DMAC_CHSTATUS reset_value) Channel Status */ + +#define DMAC_CHSTATUS_PEND_Pos 0 /**< \brief (DMAC_CHSTATUS) Channel Pending */ +#define DMAC_CHSTATUS_PEND (_U_(0x1) << DMAC_CHSTATUS_PEND_Pos) +#define DMAC_CHSTATUS_BUSY_Pos 1 /**< \brief (DMAC_CHSTATUS) Channel Busy */ +#define DMAC_CHSTATUS_BUSY (_U_(0x1) << DMAC_CHSTATUS_BUSY_Pos) +#define DMAC_CHSTATUS_FERR_Pos 2 /**< \brief (DMAC_CHSTATUS) Channel Fetch Error */ +#define DMAC_CHSTATUS_FERR (_U_(0x1) << DMAC_CHSTATUS_FERR_Pos) +#define DMAC_CHSTATUS_MASK _U_(0x07) /**< \brief (DMAC_CHSTATUS) MASK Register */ + +/* -------- DMAC_BTCTRL : (DMAC Offset: 0x00) (R/W 16) Block Transfer Control -------- */ +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +typedef union { + struct { + uint16_t VALID:1; /*!< bit: 0 Descriptor Valid */ + uint16_t EVOSEL:2; /*!< bit: 1.. 2 Event Output Selection */ + uint16_t BLOCKACT:2; /*!< bit: 3.. 4 Block Action */ + uint16_t :3; /*!< bit: 5.. 7 Reserved */ + uint16_t BEATSIZE:2; /*!< bit: 8.. 9 Beat Size */ + uint16_t SRCINC:1; /*!< bit: 10 Source Address Increment Enable */ + uint16_t DSTINC:1; /*!< bit: 11 Destination Address Increment Enable */ + uint16_t STEPSEL:1; /*!< bit: 12 Step Selection */ + uint16_t STEPSIZE:3; /*!< bit: 13..15 Address Increment Step Size */ + } bit; /*!< Structure used for bit access */ + uint16_t reg; /*!< Type used for register access */ +} DMAC_BTCTRL_Type; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ + +#define DMAC_BTCTRL_OFFSET 0x00 /**< \brief (DMAC_BTCTRL offset) Block Transfer Control */ +#define DMAC_BTCTRL_RESETVALUE _U_(0x0000) /**< \brief (DMAC_BTCTRL reset_value) Block Transfer Control */ + +#define DMAC_BTCTRL_VALID_Pos 0 /**< \brief (DMAC_BTCTRL) Descriptor Valid */ +#define DMAC_BTCTRL_VALID (_U_(0x1) << DMAC_BTCTRL_VALID_Pos) +#define DMAC_BTCTRL_EVOSEL_Pos 1 /**< \brief (DMAC_BTCTRL) Event Output Selection */ +#define DMAC_BTCTRL_EVOSEL_Msk (_U_(0x3) << DMAC_BTCTRL_EVOSEL_Pos) +#define DMAC_BTCTRL_EVOSEL(value) (DMAC_BTCTRL_EVOSEL_Msk & ((value) << DMAC_BTCTRL_EVOSEL_Pos)) +#define DMAC_BTCTRL_EVOSEL_DISABLE_Val _U_(0x0) /**< \brief (DMAC_BTCTRL) Event generation disabled */ +#define DMAC_BTCTRL_EVOSEL_BLOCK_Val _U_(0x1) /**< \brief (DMAC_BTCTRL) Event strobe when block transfer complete */ +#define DMAC_BTCTRL_EVOSEL_BEAT_Val _U_(0x3) /**< \brief (DMAC_BTCTRL) Event strobe when beat transfer complete */ +#define DMAC_BTCTRL_EVOSEL_DISABLE (DMAC_BTCTRL_EVOSEL_DISABLE_Val << DMAC_BTCTRL_EVOSEL_Pos) +#define DMAC_BTCTRL_EVOSEL_BLOCK (DMAC_BTCTRL_EVOSEL_BLOCK_Val << DMAC_BTCTRL_EVOSEL_Pos) +#define DMAC_BTCTRL_EVOSEL_BEAT (DMAC_BTCTRL_EVOSEL_BEAT_Val << DMAC_BTCTRL_EVOSEL_Pos) +#define DMAC_BTCTRL_BLOCKACT_Pos 3 /**< \brief (DMAC_BTCTRL) Block Action */ +#define DMAC_BTCTRL_BLOCKACT_Msk (_U_(0x3) << DMAC_BTCTRL_BLOCKACT_Pos) +#define DMAC_BTCTRL_BLOCKACT(value) (DMAC_BTCTRL_BLOCKACT_Msk & ((value) << DMAC_BTCTRL_BLOCKACT_Pos)) +#define DMAC_BTCTRL_BLOCKACT_NOACT_Val _U_(0x0) /**< \brief (DMAC_BTCTRL) Channel will be disabled if it is the last block transfer in the transaction */ +#define DMAC_BTCTRL_BLOCKACT_INT_Val _U_(0x1) /**< \brief (DMAC_BTCTRL) Channel will be disabled if it is the last block transfer in the transaction and block interrupt */ +#define DMAC_BTCTRL_BLOCKACT_SUSPEND_Val _U_(0x2) /**< \brief (DMAC_BTCTRL) Channel suspend operation is completed */ +#define DMAC_BTCTRL_BLOCKACT_BOTH_Val _U_(0x3) /**< \brief (DMAC_BTCTRL) Both channel suspend operation and block interrupt */ +#define DMAC_BTCTRL_BLOCKACT_NOACT (DMAC_BTCTRL_BLOCKACT_NOACT_Val << DMAC_BTCTRL_BLOCKACT_Pos) +#define DMAC_BTCTRL_BLOCKACT_INT (DMAC_BTCTRL_BLOCKACT_INT_Val << DMAC_BTCTRL_BLOCKACT_Pos) +#define DMAC_BTCTRL_BLOCKACT_SUSPEND (DMAC_BTCTRL_BLOCKACT_SUSPEND_Val << DMAC_BTCTRL_BLOCKACT_Pos) +#define DMAC_BTCTRL_BLOCKACT_BOTH (DMAC_BTCTRL_BLOCKACT_BOTH_Val << DMAC_BTCTRL_BLOCKACT_Pos) +#define DMAC_BTCTRL_BEATSIZE_Pos 8 /**< \brief (DMAC_BTCTRL) Beat Size */ +#define DMAC_BTCTRL_BEATSIZE_Msk (_U_(0x3) << DMAC_BTCTRL_BEATSIZE_Pos) +#define DMAC_BTCTRL_BEATSIZE(value) (DMAC_BTCTRL_BEATSIZE_Msk & ((value) << DMAC_BTCTRL_BEATSIZE_Pos)) +#define DMAC_BTCTRL_BEATSIZE_BYTE_Val _U_(0x0) /**< \brief (DMAC_BTCTRL) 8-bit bus transfer */ +#define DMAC_BTCTRL_BEATSIZE_HWORD_Val _U_(0x1) /**< \brief (DMAC_BTCTRL) 16-bit bus transfer */ +#define DMAC_BTCTRL_BEATSIZE_WORD_Val _U_(0x2) /**< \brief (DMAC_BTCTRL) 32-bit bus transfer */ +#define DMAC_BTCTRL_BEATSIZE_BYTE (DMAC_BTCTRL_BEATSIZE_BYTE_Val << DMAC_BTCTRL_BEATSIZE_Pos) +#define DMAC_BTCTRL_BEATSIZE_HWORD (DMAC_BTCTRL_BEATSIZE_HWORD_Val << DMAC_BTCTRL_BEATSIZE_Pos) +#define DMAC_BTCTRL_BEATSIZE_WORD (DMAC_BTCTRL_BEATSIZE_WORD_Val << DMAC_BTCTRL_BEATSIZE_Pos) +#define DMAC_BTCTRL_SRCINC_Pos 10 /**< \brief (DMAC_BTCTRL) Source Address Increment Enable */ +#define DMAC_BTCTRL_SRCINC (_U_(0x1) << DMAC_BTCTRL_SRCINC_Pos) +#define DMAC_BTCTRL_DSTINC_Pos 11 /**< \brief (DMAC_BTCTRL) Destination Address Increment Enable */ +#define DMAC_BTCTRL_DSTINC (_U_(0x1) << DMAC_BTCTRL_DSTINC_Pos) +#define DMAC_BTCTRL_STEPSEL_Pos 12 /**< \brief (DMAC_BTCTRL) Step Selection */ +#define DMAC_BTCTRL_STEPSEL (_U_(0x1) << DMAC_BTCTRL_STEPSEL_Pos) +#define DMAC_BTCTRL_STEPSEL_DST_Val _U_(0x0) /**< \brief (DMAC_BTCTRL) Step size settings apply to the destination address */ +#define DMAC_BTCTRL_STEPSEL_SRC_Val _U_(0x1) /**< \brief (DMAC_BTCTRL) Step size settings apply to the source address */ +#define DMAC_BTCTRL_STEPSEL_DST (DMAC_BTCTRL_STEPSEL_DST_Val << DMAC_BTCTRL_STEPSEL_Pos) +#define DMAC_BTCTRL_STEPSEL_SRC (DMAC_BTCTRL_STEPSEL_SRC_Val << DMAC_BTCTRL_STEPSEL_Pos) +#define DMAC_BTCTRL_STEPSIZE_Pos 13 /**< \brief (DMAC_BTCTRL) Address Increment Step Size */ +#define DMAC_BTCTRL_STEPSIZE_Msk (_U_(0x7) << DMAC_BTCTRL_STEPSIZE_Pos) +#define DMAC_BTCTRL_STEPSIZE(value) (DMAC_BTCTRL_STEPSIZE_Msk & ((value) << DMAC_BTCTRL_STEPSIZE_Pos)) +#define DMAC_BTCTRL_STEPSIZE_X1_Val _U_(0x0) /**< \brief (DMAC_BTCTRL) Next ADDR = ADDR + (1< +#ifndef __cplusplus +typedef volatile const uint32_t RoReg; /**< Read only 32-bit register (volatile const unsigned int) */ +typedef volatile const uint16_t RoReg16; /**< Read only 16-bit register (volatile const unsigned int) */ +typedef volatile const uint8_t RoReg8; /**< Read only 8-bit register (volatile const unsigned int) */ +#else +typedef volatile uint32_t RoReg; /**< Read only 32-bit register (volatile const unsigned int) */ +typedef volatile uint16_t RoReg16; /**< Read only 16-bit register (volatile const unsigned int) */ +typedef volatile uint8_t RoReg8; /**< Read only 8-bit register (volatile const unsigned int) */ +#endif +typedef volatile uint32_t WoReg; /**< Write only 32-bit register (volatile unsigned int) */ +typedef volatile uint16_t WoReg16; /**< Write only 16-bit register (volatile unsigned int) */ +typedef volatile uint8_t WoReg8; /**< Write only 8-bit register (volatile unsigned int) */ +typedef volatile uint32_t RwReg; /**< Read-Write 32-bit register (volatile unsigned int) */ +typedef volatile uint16_t RwReg16; /**< Read-Write 16-bit register (volatile unsigned int) */ +typedef volatile uint8_t RwReg8; /**< Read-Write 8-bit register (volatile unsigned int) */ +#endif + +#if !defined(SKIP_INTEGER_LITERALS) +#if defined(_U_) || defined(_L_) || defined(_UL_) + #error "Integer Literals macros already defined elsewhere" +#endif + +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +/* Macros that deal with adding suffixes to integer literal constants for C/C++ */ +#define _U_(x) x ## U /**< C code: Unsigned integer literal constant value */ +#define _L_(x) x ## L /**< C code: Long integer literal constant value */ +#define _UL_(x) x ## UL /**< C code: Unsigned Long integer literal constant value */ +#else /* Assembler */ +#define _U_(x) x /**< Assembler: Unsigned integer literal constant value */ +#define _L_(x) x /**< Assembler: Long integer literal constant value */ +#define _UL_(x) x /**< Assembler: Unsigned Long integer literal constant value */ +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ +#endif /* SKIP_INTEGER_LITERALS */ + +/* ************************************************************************** */ +/** CMSIS DEFINITIONS FOR SAMR34J16B */ +/* ************************************************************************** */ +/** \defgroup SAMR34J16B_cmsis CMSIS Definitions */ +/*@{*/ + +/** Interrupt Number Definition */ +typedef enum IRQn +{ + /****** Cortex-M0+ Processor Exceptions Numbers ******************************/ + NonMaskableInt_IRQn = -14,/**< 2 Non Maskable Interrupt */ + HardFault_IRQn = -13,/**< 3 Cortex-M0+ Hard Fault Interrupt */ + SVCall_IRQn = -5, /**< 11 Cortex-M0+ SV Call Interrupt */ + PendSV_IRQn = -2, /**< 14 Cortex-M0+ Pend SV Interrupt */ + SysTick_IRQn = -1, /**< 15 Cortex-M0+ System Tick Interrupt */ + /****** SAMR34J16B-specific Interrupt Numbers ***********************/ + SYSTEM_IRQn = 0, /**< 0 SAMR34J16B System Interrupts */ + WDT_IRQn = 1, /**< 1 SAMR34J16B Watchdog Timer (WDT) */ + RTC_IRQn = 2, /**< 2 SAMR34J16B Real-Time Counter (RTC) */ + EIC_IRQn = 3, /**< 3 SAMR34J16B External Interrupt Controller (EIC) */ + NVMCTRL_IRQn = 4, /**< 4 SAMR34J16B Non-Volatile Memory Controller (NVMCTRL) */ + DMAC_IRQn = 5, /**< 5 SAMR34J16B Direct Memory Access Controller (DMAC) */ + USB_IRQn = 6, /**< 6 SAMR34J16B Universal Serial Bus (USB) */ + EVSYS_IRQn = 7, /**< 7 SAMR34J16B Event System Interface (EVSYS) */ + SERCOM0_IRQn = 8, /**< 8 SAMR34J16B Serial Communication Interface 0 (SERCOM0) */ + SERCOM1_IRQn = 9, /**< 9 SAMR34J16B Serial Communication Interface 1 (SERCOM1) */ + SERCOM2_IRQn = 10, /**< 10 SAMR34J16B Serial Communication Interface 2 (SERCOM2) */ + SERCOM3_IRQn = 11, /**< 11 SAMR34J16B Serial Communication Interface 3 (SERCOM3) */ + SERCOM4_IRQn = 12, /**< 12 SAMR34J16B Serial Communication Interface 4 (SERCOM4) */ + SERCOM5_IRQn = 13, /**< 13 SAMR34J16B Serial Communication Interface 5 (SERCOM5) */ + TCC0_IRQn = 14, /**< 14 SAMR34J16B Timer Counter Control 0 (TCC0) */ + TCC1_IRQn = 15, /**< 15 SAMR34J16B Timer Counter Control 1 (TCC1) */ + TCC2_IRQn = 16, /**< 16 SAMR34J16B Timer Counter Control 2 (TCC2) */ + TC0_IRQn = 17, /**< 17 SAMR34J16B Basic Timer Counter 0 (TC0) */ + TC1_IRQn = 18, /**< 18 SAMR34J16B Basic Timer Counter 1 (TC1) */ + TC2_IRQn = 19, /**< 19 SAMR34J16B Basic Timer Counter 2 (TC2) */ + TC3_IRQn = 20, /**< 20 SAMR34J16B Basic Timer Counter 3 (TC3) */ + TC4_IRQn = 21, /**< 21 SAMR34J16B Basic Timer Counter 4 (TC4) */ + ADC_IRQn = 22, /**< 22 SAMR34J16B Analog Digital Converter (ADC) */ + AC_IRQn = 23, /**< 23 SAMR34J16B Analog Comparators (AC) */ + DAC_IRQn = 24, /**< 24 SAMR34J16B Digital-to-Analog Converter (DAC) */ + PTC_IRQn = 25, /**< 25 SAMR34J16B Peripheral Touch Controller (PTC) */ + AES_IRQn = 26, /**< 26 SAMR34J16B Advanced Encryption Standard (AES) */ + TRNG_IRQn = 27, /**< 27 SAMR34J16B True Random Generator (TRNG) */ + + PERIPH_COUNT_IRQn = 29 /**< Number of peripheral IDs */ +} IRQn_Type; + +typedef struct _DeviceVectors +{ + /* Stack pointer */ + void* pvStack; + + /* Cortex-M handlers */ + void* pfnReset_Handler; + void* pfnNMI_Handler; + void* pfnHardFault_Handler; + void* pvReservedM12; + void* pvReservedM11; + void* pvReservedM10; + void* pvReservedM9; + void* pvReservedM8; + void* pvReservedM7; + void* pvReservedM6; + void* pfnSVC_Handler; + void* pvReservedM4; + void* pvReservedM3; + void* pfnPendSV_Handler; + void* pfnSysTick_Handler; + + /* Peripheral handlers */ + void* pfnSYSTEM_Handler; /* 0 Main Clock, 32k Oscillators Control, Oscillators Control, Peripheral Access Controller, Power Manager, Supply Controller, Trigger Allocator */ + void* pfnWDT_Handler; /* 1 Watchdog Timer */ + void* pfnRTC_Handler; /* 2 Real-Time Counter */ + void* pfnEIC_Handler; /* 3 External Interrupt Controller */ + void* pfnNVMCTRL_Handler; /* 4 Non-Volatile Memory Controller */ + void* pfnDMAC_Handler; /* 5 Direct Memory Access Controller */ + void* pfnUSB_Handler; /* 6 Universal Serial Bus */ + void* pfnEVSYS_Handler; /* 7 Event System Interface */ + void* pfnSERCOM0_Handler; /* 8 Serial Communication Interface 0 */ + void* pfnSERCOM1_Handler; /* 9 Serial Communication Interface 1 */ + void* pfnSERCOM2_Handler; /* 10 Serial Communication Interface 2 */ + void* pfnSERCOM3_Handler; /* 11 Serial Communication Interface 3 */ + void* pfnSERCOM4_Handler; /* 12 Serial Communication Interface 4 */ + void* pfnSERCOM5_Handler; /* 13 Serial Communication Interface 5 */ + void* pfnTCC0_Handler; /* 14 Timer Counter Control 0 */ + void* pfnTCC1_Handler; /* 15 Timer Counter Control 1 */ + void* pfnTCC2_Handler; /* 16 Timer Counter Control 2 */ + void* pfnTC0_Handler; /* 17 Basic Timer Counter 0 */ + void* pfnTC1_Handler; /* 18 Basic Timer Counter 1 */ + void* pfnTC2_Handler; /* 19 Basic Timer Counter 2 */ + void* pfnTC3_Handler; /* 20 Basic Timer Counter 3 */ + void* pfnTC4_Handler; /* 21 Basic Timer Counter 4 */ + void* pfnADC_Handler; /* 22 Analog Digital Converter */ + void* pfnAC_Handler; /* 23 Analog Comparators */ + void* pfnDAC_Handler; /* 24 Digital-to-Analog Converter */ + void* pfnPTC_Handler; /* 25 Peripheral Touch Controller */ + void* pfnAES_Handler; /* 26 Advanced Encryption Standard */ + void* pfnTRNG_Handler; /* 27 True Random Generator */ + void* pvReserved28; +} DeviceVectors; + +/* Cortex-M0+ processor handlers */ +void Reset_Handler ( void ); +void NMI_Handler ( void ); +void HardFault_Handler ( void ); +void SVC_Handler ( void ); +void PendSV_Handler ( void ); +void SysTick_Handler ( void ); + +/* Peripherals handlers */ +void SYSTEM_Handler ( void ); +void WDT_Handler ( void ); +void RTC_Handler ( void ); +void EIC_Handler ( void ); +void NVMCTRL_Handler ( void ); +void DMAC_Handler ( void ); +void USB_Handler ( void ); +void EVSYS_Handler ( void ); +void SERCOM0_Handler ( void ); +void SERCOM1_Handler ( void ); +void SERCOM2_Handler ( void ); +void SERCOM3_Handler ( void ); +void SERCOM4_Handler ( void ); +void SERCOM5_Handler ( void ); +void TCC0_Handler ( void ); +void TCC1_Handler ( void ); +void TCC2_Handler ( void ); +void TC0_Handler ( void ); +void TC1_Handler ( void ); +void TC2_Handler ( void ); +void TC3_Handler ( void ); +void TC4_Handler ( void ); +void ADC_Handler ( void ); +void AC_Handler ( void ); +void DAC_Handler ( void ); +void PTC_Handler ( void ); +void AES_Handler ( void ); +void TRNG_Handler ( void ); + +/* + * \brief Configuration of the Cortex-M0+ Processor and Core Peripherals + */ + +#define LITTLE_ENDIAN 1 +#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */ +#define __MPU_PRESENT 0 /*!< MPU present or not */ +#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */ +#define __VTOR_PRESENT 1 /*!< VTOR present or not */ +#define __Vendor_SysTickConfig 0 /*!< Set to 1 if different SysTick Config is used */ + +/** + * \brief CMSIS includes + */ + +#include +#if !defined DONT_USE_CMSIS_INIT +#include "system_samr34.h" +#endif /* DONT_USE_CMSIS_INIT */ + +/*@}*/ + +/* ************************************************************************** */ +/** SOFTWARE PERIPHERAL API DEFINITION FOR SAMR34J16B */ +/* ************************************************************************** */ +/** \defgroup SAMR34J16B_api Peripheral Software API */ +/*@{*/ + +#include "component/ac.h" +#include "component/adc.h" +#include "component/aes.h" +#include "component/ccl.h" +#include "component/dac.h" +#include "component/dmac.h" +#include "component/dsu.h" +#include "component/eic.h" +#include "component/evsys.h" +#include "component/gclk.h" +#include "component/mclk.h" +#include "component/mtb.h" +#include "component/nvmctrl.h" +#include "component/oscctrl.h" +#include "component/osc32kctrl.h" +#include "component/pac.h" +#include "component/pm.h" +#include "component/port.h" +#include "component/rstc.h" +#include "component/rtc.h" +#include "component/sercom.h" +#include "component/supc.h" +#include "component/tal.h" +#include "component/tc.h" +#include "component/tcc.h" +#include "component/trng.h" +#include "component/usb.h" +#include "component/wdt.h" +/*@}*/ + +/* ************************************************************************** */ +/** REGISTERS ACCESS DEFINITIONS FOR SAMR34J16B */ +/* ************************************************************************** */ +/** \defgroup SAMR34J16B_reg Registers Access Definitions */ +/*@{*/ + +#include "instance/ac.h" +#include "instance/adc.h" +#include "instance/aes.h" +#include "instance/ccl.h" +#include "instance/dac.h" +#include "instance/dmac.h" +#include "instance/dsu.h" +#include "instance/eic.h" +#include "instance/evsys.h" +#include "instance/gclk.h" +#include "instance/mclk.h" +#include "instance/mtb.h" +#include "instance/nvmctrl.h" +#include "instance/oscctrl.h" +#include "instance/osc32kctrl.h" +#include "instance/pac.h" +#include "instance/pm.h" +#include "instance/port.h" +#include "instance/rstc.h" +#include "instance/rtc.h" +#include "instance/sercom0.h" +#include "instance/sercom1.h" +#include "instance/sercom2.h" +#include "instance/sercom3.h" +#include "instance/sercom4.h" +#include "instance/sercom5.h" +#include "instance/supc.h" +#include "instance/tal.h" +#include "instance/tc0.h" +#include "instance/tc1.h" +#include "instance/tc2.h" +#include "instance/tc3.h" +#include "instance/tc4.h" +#include "instance/tcc0.h" +#include "instance/tcc1.h" +#include "instance/tcc2.h" +#include "instance/trng.h" +#include "instance/usb.h" +#include "instance/wdt.h" +/*@}*/ + +/* ************************************************************************** */ +/** PERIPHERAL ID DEFINITIONS FOR SAMR34J16B */ +/* ************************************************************************** */ +/** \defgroup SAMR34J16B_id Peripheral Ids Definitions */ +/*@{*/ + +// Peripheral instances on HPB0 bridge +#define ID_PM 0 /**< \brief Power Manager (PM) */ +#define ID_MCLK 1 /**< \brief Main Clock (MCLK) */ +#define ID_RSTC 2 /**< \brief Reset Controller (RSTC) */ +#define ID_OSCCTRL 3 /**< \brief Oscillators Control (OSCCTRL) */ +#define ID_OSC32KCTRL 4 /**< \brief 32k Oscillators Control (OSC32KCTRL) */ +#define ID_SUPC 5 /**< \brief Supply Controller (SUPC) */ +#define ID_GCLK 6 /**< \brief Generic Clock Generator (GCLK) */ +#define ID_WDT 7 /**< \brief Watchdog Timer (WDT) */ +#define ID_RTC 8 /**< \brief Real-Time Counter (RTC) */ +#define ID_EIC 9 /**< \brief External Interrupt Controller (EIC) */ +#define ID_PORT 10 /**< \brief Port Module (PORT) */ +#define ID_TAL 11 /**< \brief Trigger Allocator (TAL) */ + +// Peripheral instances on HPB1 bridge +#define ID_USB 32 /**< \brief Universal Serial Bus (USB) */ +#define ID_DSU 33 /**< \brief Device Service Unit (DSU) */ +#define ID_NVMCTRL 34 /**< \brief Non-Volatile Memory Controller (NVMCTRL) */ +#define ID_MTB 35 /**< \brief Cortex-M0+ Micro-Trace Buffer (MTB) */ + +// Peripheral instances on HPB2 bridge +#define ID_SERCOM0 64 /**< \brief Serial Communication Interface 0 (SERCOM0) */ +#define ID_SERCOM1 65 /**< \brief Serial Communication Interface 1 (SERCOM1) */ +#define ID_SERCOM2 66 /**< \brief Serial Communication Interface 2 (SERCOM2) */ +#define ID_SERCOM3 67 /**< \brief Serial Communication Interface 3 (SERCOM3) */ +#define ID_SERCOM4 68 /**< \brief Serial Communication Interface 4 (SERCOM4) */ +#define ID_TCC0 69 /**< \brief Timer Counter Control 0 (TCC0) */ +#define ID_TCC1 70 /**< \brief Timer Counter Control 1 (TCC1) */ +#define ID_TCC2 71 /**< \brief Timer Counter Control 2 (TCC2) */ +#define ID_TC0 72 /**< \brief Basic Timer Counter 0 (TC0) */ +#define ID_TC1 73 /**< \brief Basic Timer Counter 1 (TC1) */ +#define ID_TC2 74 /**< \brief Basic Timer Counter 2 (TC2) */ +#define ID_TC3 75 /**< \brief Basic Timer Counter 3 (TC3) */ +#define ID_DAC 76 /**< \brief Digital-to-Analog Converter (DAC) */ +#define ID_AES 77 /**< \brief Advanced Encryption Standard (AES) */ +#define ID_TRNG 78 /**< \brief True Random Generator (TRNG) */ + +// Peripheral instances on HPB3 bridge +#define ID_EVSYS 96 /**< \brief Event System Interface (EVSYS) */ +#define ID_SERCOM5 97 /**< \brief Serial Communication Interface 5 (SERCOM5) */ +#define ID_TC4 98 /**< \brief Basic Timer Counter 4 (TC4) */ +#define ID_ADC 99 /**< \brief Analog Digital Converter (ADC) */ +#define ID_AC 100 /**< \brief Analog Comparators (AC) */ +#define ID_PTC 101 /**< \brief Peripheral Touch Controller (PTC) */ +#define ID_CCL 103 /**< \brief Configurable Custom Logic (CCL) */ + +// Peripheral instances on HPB4 bridge +#define ID_PAC 128 /**< \brief Peripheral Access Controller (PAC) */ +#define ID_DMAC 129 /**< \brief Direct Memory Access Controller (DMAC) */ + +#define ID_PERIPH_COUNT 130 /**< \brief Max number of peripheral IDs */ +/*@}*/ + +/* ************************************************************************** */ +/** BASE ADDRESS DEFINITIONS FOR SAMR34J16B */ +/* ************************************************************************** */ +/** \defgroup SAMR34J16B_base Peripheral Base Address Definitions */ +/*@{*/ + +#if defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__) +#define AC (0x43001000) /**< \brief (AC) APB Base Address */ +#define ADC (0x43000C00) /**< \brief (ADC) APB Base Address */ +#define AES (0x42003400) /**< \brief (AES) APB Base Address */ +#define CCL (0x43001C00) /**< \brief (CCL) APB Base Address */ +#define DAC (0x42003000) /**< \brief (DAC) APB Base Address */ +#define DMAC (0x44000400) /**< \brief (DMAC) APB Base Address */ +#define DSU (0x41002000) /**< \brief (DSU) APB Base Address */ +#define EIC (0x40002400) /**< \brief (EIC) APB Base Address */ +#define EVSYS (0x43000000) /**< \brief (EVSYS) APB Base Address */ +#define GCLK (0x40001800) /**< \brief (GCLK) APB Base Address */ +#define MCLK (0x40000400) /**< \brief (MCLK) APB Base Address */ +#define MTB (0x41006000) /**< \brief (MTB) APB Base Address */ +#define NVMCTRL (0x41004000) /**< \brief (NVMCTRL) APB Base Address */ +#define NVMCTRL_CAL (0x00800000) /**< \brief (NVMCTRL) CAL Base Address */ +#define NVMCTRL_LOCKBIT (0x00802000) /**< \brief (NVMCTRL) LOCKBIT Base Address */ +#define NVMCTRL_OTP1 (0x00806000) /**< \brief (NVMCTRL) OTP1 Base Address */ +#define NVMCTRL_OTP2 (0x00806008) /**< \brief (NVMCTRL) OTP2 Base Address */ +#define NVMCTRL_OTP3 (0x00806010) /**< \brief (NVMCTRL) OTP3 Base Address */ +#define NVMCTRL_OTP4 (0x00806018) /**< \brief (NVMCTRL) OTP4 Base Address */ +#define NVMCTRL_OTP5 (0x00806020) /**< \brief (NVMCTRL) OTP5 Base Address */ +#define NVMCTRL_TEMP_LOG (0x00806030) /**< \brief (NVMCTRL) TEMP_LOG Base Address */ +#define NVMCTRL_USER (0x00804000) /**< \brief (NVMCTRL) USER Base Address */ +#define OSCCTRL (0x40000C00) /**< \brief (OSCCTRL) APB Base Address */ +#define OSC32KCTRL (0x40001000) /**< \brief (OSC32KCTRL) APB Base Address */ +#define PAC (0x44000000) /**< \brief (PAC) APB Base Address */ +#define PM (0x40000000) /**< \brief (PM) APB Base Address */ +#define PORT (0x40002800) /**< \brief (PORT) APB Base Address */ +#define PORT_IOBUS (0x60000000) /**< \brief (PORT) IOBUS Base Address */ +#define PTC (0x43001400) /**< \brief (PTC) APB Base Address */ +#define RSTC (0x40000800) /**< \brief (RSTC) APB Base Address */ +#define RTC (0x40002000) /**< \brief (RTC) APB Base Address */ +#define SERCOM0 (0x42000000) /**< \brief (SERCOM0) APB Base Address */ +#define SERCOM1 (0x42000400) /**< \brief (SERCOM1) APB Base Address */ +#define SERCOM2 (0x42000800) /**< \brief (SERCOM2) APB Base Address */ +#define SERCOM3 (0x42000C00) /**< \brief (SERCOM3) APB Base Address */ +#define SERCOM4 (0x42001000) /**< \brief (SERCOM4) APB Base Address */ +#define SERCOM5 (0x43000400) /**< \brief (SERCOM5) APB Base Address */ +#define SUPC (0x40001400) /**< \brief (SUPC) APB Base Address */ +#define TAL (0x40002C00) /**< \brief (TAL) APB Base Address */ +#define TC0 (0x42002000) /**< \brief (TC0) APB Base Address */ +#define TC1 (0x42002400) /**< \brief (TC1) APB Base Address */ +#define TC2 (0x42002800) /**< \brief (TC2) APB Base Address */ +#define TC3 (0x42002C00) /**< \brief (TC3) APB Base Address */ +#define TC4 (0x43000800) /**< \brief (TC4) APB Base Address */ +#define TCC0 (0x42001400) /**< \brief (TCC0) APB Base Address */ +#define TCC1 (0x42001800) /**< \brief (TCC1) APB Base Address */ +#define TCC2 (0x42001C00) /**< \brief (TCC2) APB Base Address */ +#define TRNG (0x42003800) /**< \brief (TRNG) APB Base Address */ +#define USB (0x41000000) /**< \brief (USB) APB Base Address */ +#define WDT (0x40001C00) /**< \brief (WDT) APB Base Address */ +#else +#define AC ((Ac *)0x43001000UL) /**< \brief (AC) APB Base Address */ +#define AC_INST_NUM 1 /**< \brief (AC) Number of instances */ +#define AC_INSTS { AC } /**< \brief (AC) Instances List */ + +#define ADC ((Adc *)0x43000C00UL) /**< \brief (ADC) APB Base Address */ +#define ADC_INST_NUM 1 /**< \brief (ADC) Number of instances */ +#define ADC_INSTS { ADC } /**< \brief (ADC) Instances List */ + +#define AES ((Aes *)0x42003400UL) /**< \brief (AES) APB Base Address */ +#define AES_INST_NUM 1 /**< \brief (AES) Number of instances */ +#define AES_INSTS { AES } /**< \brief (AES) Instances List */ + +#define CCL ((Ccl *)0x43001C00UL) /**< \brief (CCL) APB Base Address */ +#define CCL_INST_NUM 1 /**< \brief (CCL) Number of instances */ +#define CCL_INSTS { CCL } /**< \brief (CCL) Instances List */ + +#define DAC ((Dac *)0x42003000UL) /**< \brief (DAC) APB Base Address */ +#define DAC_INST_NUM 1 /**< \brief (DAC) Number of instances */ +#define DAC_INSTS { DAC } /**< \brief (DAC) Instances List */ + +#define DMAC ((Dmac *)0x44000400UL) /**< \brief (DMAC) APB Base Address */ +#define DMAC_INST_NUM 1 /**< \brief (DMAC) Number of instances */ +#define DMAC_INSTS { DMAC } /**< \brief (DMAC) Instances List */ + +#define DSU ((Dsu *)0x41002000UL) /**< \brief (DSU) APB Base Address */ +#define DSU_INST_NUM 1 /**< \brief (DSU) Number of instances */ +#define DSU_INSTS { DSU } /**< \brief (DSU) Instances List */ + +#define EIC ((Eic *)0x40002400UL) /**< \brief (EIC) APB Base Address */ +#define EIC_INST_NUM 1 /**< \brief (EIC) Number of instances */ +#define EIC_INSTS { EIC } /**< \brief (EIC) Instances List */ + +#define EVSYS ((Evsys *)0x43000000UL) /**< \brief (EVSYS) APB Base Address */ +#define EVSYS_INST_NUM 1 /**< \brief (EVSYS) Number of instances */ +#define EVSYS_INSTS { EVSYS } /**< \brief (EVSYS) Instances List */ + +#define GCLK ((Gclk *)0x40001800UL) /**< \brief (GCLK) APB Base Address */ +#define GCLK_INST_NUM 1 /**< \brief (GCLK) Number of instances */ +#define GCLK_INSTS { GCLK } /**< \brief (GCLK) Instances List */ + +#define MCLK ((Mclk *)0x40000400UL) /**< \brief (MCLK) APB Base Address */ +#define MCLK_INST_NUM 1 /**< \brief (MCLK) Number of instances */ +#define MCLK_INSTS { MCLK } /**< \brief (MCLK) Instances List */ + +#define MTB ((Mtb *)0x41006000UL) /**< \brief (MTB) APB Base Address */ +#define MTB_INST_NUM 1 /**< \brief (MTB) Number of instances */ +#define MTB_INSTS { MTB } /**< \brief (MTB) Instances List */ + +#define NVMCTRL ((Nvmctrl *)0x41004000UL) /**< \brief (NVMCTRL) APB Base Address */ +#define NVMCTRL_CAL (0x00800000UL) /**< \brief (NVMCTRL) CAL Base Address */ +#define NVMCTRL_LOCKBIT (0x00802000UL) /**< \brief (NVMCTRL) LOCKBIT Base Address */ +#define NVMCTRL_OTP1 (0x00806000UL) /**< \brief (NVMCTRL) OTP1 Base Address */ +#define NVMCTRL_OTP2 (0x00806008UL) /**< \brief (NVMCTRL) OTP2 Base Address */ +#define NVMCTRL_OTP3 (0x00806010UL) /**< \brief (NVMCTRL) OTP3 Base Address */ +#define NVMCTRL_OTP4 (0x00806018UL) /**< \brief (NVMCTRL) OTP4 Base Address */ +#define NVMCTRL_OTP5 (0x00806020UL) /**< \brief (NVMCTRL) OTP5 Base Address */ +#define NVMCTRL_TEMP_LOG (0x00806030UL) /**< \brief (NVMCTRL) TEMP_LOG Base Address */ +#define NVMCTRL_USER (0x00804000UL) /**< \brief (NVMCTRL) USER Base Address */ +#define NVMCTRL_INST_NUM 1 /**< \brief (NVMCTRL) Number of instances */ +#define NVMCTRL_INSTS { NVMCTRL } /**< \brief (NVMCTRL) Instances List */ + +#define OSCCTRL ((Oscctrl *)0x40000C00UL) /**< \brief (OSCCTRL) APB Base Address */ +#define OSCCTRL_INST_NUM 1 /**< \brief (OSCCTRL) Number of instances */ +#define OSCCTRL_INSTS { OSCCTRL } /**< \brief (OSCCTRL) Instances List */ + +#define OSC32KCTRL ((Osc32kctrl *)0x40001000UL) /**< \brief (OSC32KCTRL) APB Base Address */ +#define OSC32KCTRL_INST_NUM 1 /**< \brief (OSC32KCTRL) Number of instances */ +#define OSC32KCTRL_INSTS { OSC32KCTRL } /**< \brief (OSC32KCTRL) Instances List */ + +#define PAC ((Pac *)0x44000000UL) /**< \brief (PAC) APB Base Address */ +#define PAC_INST_NUM 1 /**< \brief (PAC) Number of instances */ +#define PAC_INSTS { PAC } /**< \brief (PAC) Instances List */ + +#define PM ((Pm *)0x40000000UL) /**< \brief (PM) APB Base Address */ +#define PM_INST_NUM 1 /**< \brief (PM) Number of instances */ +#define PM_INSTS { PM } /**< \brief (PM) Instances List */ + +#define PORT ((Port *)0x40002800UL) /**< \brief (PORT) APB Base Address */ +#define PORT_IOBUS ((Port *)0x60000000UL) /**< \brief (PORT) IOBUS Base Address */ +#define PORT_INST_NUM 1 /**< \brief (PORT) Number of instances */ +#define PORT_INSTS { PORT } /**< \brief (PORT) Instances List */ +#define PORT_IOBUS_INST_NUM 1 /**< \brief (PORT) Number of instances */ +#define PORT_IOBUS_INSTS { PORT_IOBUS } /**< \brief (PORT) Instances List */ + +#define PTC ((void *)0x43001400UL) /**< \brief (PTC) APB Base Address */ +#define PTC_GCLK_ID 33 +#define PTC_INST_NUM 1 /**< \brief (PTC) Number of instances */ +#define PTC_INSTS { PTC } /**< \brief (PTC) Instances List */ + +#define RSTC ((Rstc *)0x40000800UL) /**< \brief (RSTC) APB Base Address */ +#define RSTC_INST_NUM 1 /**< \brief (RSTC) Number of instances */ +#define RSTC_INSTS { RSTC } /**< \brief (RSTC) Instances List */ + +#define RTC ((Rtc *)0x40002000UL) /**< \brief (RTC) APB Base Address */ +#define RTC_INST_NUM 1 /**< \brief (RTC) Number of instances */ +#define RTC_INSTS { RTC } /**< \brief (RTC) Instances List */ + +#define SERCOM0 ((Sercom *)0x42000000UL) /**< \brief (SERCOM0) APB Base Address */ +#define SERCOM1 ((Sercom *)0x42000400UL) /**< \brief (SERCOM1) APB Base Address */ +#define SERCOM2 ((Sercom *)0x42000800UL) /**< \brief (SERCOM2) APB Base Address */ +#define SERCOM3 ((Sercom *)0x42000C00UL) /**< \brief (SERCOM3) APB Base Address */ +#define SERCOM4 ((Sercom *)0x42001000UL) /**< \brief (SERCOM4) APB Base Address */ +#define SERCOM5 ((Sercom *)0x43000400UL) /**< \brief (SERCOM5) APB Base Address */ +#define SERCOM_INST_NUM 6 /**< \brief (SERCOM) Number of instances */ +#define SERCOM_INSTS { SERCOM0, SERCOM1, SERCOM2, SERCOM3, SERCOM4, SERCOM5 } /**< \brief (SERCOM) Instances List */ + +#define SUPC ((Supc *)0x40001400UL) /**< \brief (SUPC) APB Base Address */ +#define SUPC_INST_NUM 1 /**< \brief (SUPC) Number of instances */ +#define SUPC_INSTS { SUPC } /**< \brief (SUPC) Instances List */ + +#define TAL ((Tal *)0x40002C00UL) /**< \brief (TAL) APB Base Address */ +#define TAL_INST_NUM 1 /**< \brief (TAL) Number of instances */ +#define TAL_INSTS { TAL } /**< \brief (TAL) Instances List */ + +#define TC0 ((Tc *)0x42002000UL) /**< \brief (TC0) APB Base Address */ +#define TC1 ((Tc *)0x42002400UL) /**< \brief (TC1) APB Base Address */ +#define TC2 ((Tc *)0x42002800UL) /**< \brief (TC2) APB Base Address */ +#define TC3 ((Tc *)0x42002C00UL) /**< \brief (TC3) APB Base Address */ +#define TC4 ((Tc *)0x43000800UL) /**< \brief (TC4) APB Base Address */ +#define TC_INST_NUM 5 /**< \brief (TC) Number of instances */ +#define TC_INSTS { TC0, TC1, TC2, TC3, TC4 } /**< \brief (TC) Instances List */ + +#define TCC0 ((Tcc *)0x42001400UL) /**< \brief (TCC0) APB Base Address */ +#define TCC1 ((Tcc *)0x42001800UL) /**< \brief (TCC1) APB Base Address */ +#define TCC2 ((Tcc *)0x42001C00UL) /**< \brief (TCC2) APB Base Address */ +#define TCC_INST_NUM 3 /**< \brief (TCC) Number of instances */ +#define TCC_INSTS { TCC0, TCC1, TCC2 } /**< \brief (TCC) Instances List */ + +#define TRNG ((Trng *)0x42003800UL) /**< \brief (TRNG) APB Base Address */ +#define TRNG_INST_NUM 1 /**< \brief (TRNG) Number of instances */ +#define TRNG_INSTS { TRNG } /**< \brief (TRNG) Instances List */ + +#define USB ((Usb *)0x41000000UL) /**< \brief (USB) APB Base Address */ +#define USB_INST_NUM 1 /**< \brief (USB) Number of instances */ +#define USB_INSTS { USB } /**< \brief (USB) Instances List */ + +#define WDT ((Wdt *)0x40001C00UL) /**< \brief (WDT) APB Base Address */ +#define WDT_INST_NUM 1 /**< \brief (WDT) Number of instances */ +#define WDT_INSTS { WDT } /**< \brief (WDT) Instances List */ + +#endif /* (defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ +/*@}*/ + +/* ************************************************************************** */ +/** PORT DEFINITIONS FOR SAMR34J16B */ +/* ************************************************************************** */ +/** \defgroup SAMR34J16B_port PORT Definitions */ +/*@{*/ + +#include "pio/samr34j16b.h" +/*@}*/ + +/* ************************************************************************** */ +/** MEMORY MAPPING DEFINITIONS FOR SAMR34J16B */ +/* ************************************************************************** */ + +#define FLASH_SIZE _UL_(0x00010000) /* 64 kB */ +#define FLASH_PAGE_SIZE 64 +#define FLASH_NB_OF_PAGES 1024 +#define FLASH_USER_PAGE_SIZE 64 +#define HSRAM_SIZE _UL_(0x00002000) /* 8 kB */ +#define LPRAM_SIZE _UL_(0x00001000) /* 4 kB */ + +#define FLASH_ADDR _UL_(0x00000000) /**< FLASH base address */ +#define FLASH_USER_PAGE_ADDR _UL_(0x00800000) /**< FLASH_USER_PAGE base address */ +#define HSRAM_ADDR _UL_(0x20000000) /**< HSRAM base address */ +#define LPRAM_ADDR _UL_(0x30000000) /**< LPRAM base address */ +#define HPB0_ADDR _UL_(0x40000000) /**< HPB0 base address */ +#define HPB1_ADDR _UL_(0x41000000) /**< HPB1 base address */ +#define HPB2_ADDR _UL_(0x42000000) /**< HPB2 base address */ +#define HPB3_ADDR _UL_(0x43000000) /**< HPB3 base address */ +#define HPB4_ADDR _UL_(0x44000000) /**< HPB4 base address */ +#define PPB_ADDR _UL_(0xE0000000) /**< PPB base address */ + +#define DSU_DID_RESETVALUE _UL_(0x1081022A) +#define NVMCTRL_RWW_EEPROM_SIZE _UL_(0x00000800) /* 2 kB */ +#define PORT_GROUPS 3 +#define SIP_CONFIG SX1276 +#define USB_HOST_IMPLEMENTED 1 + +/* ************************************************************************** */ +/** ELECTRICAL DEFINITIONS FOR SAMR34J16B */ +/* ************************************************************************** */ + + +#ifdef __cplusplus +} +#endif + +/*@}*/ + +#endif /* SAMR34J16B_H */ diff --git a/src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/samr34j17b.h b/src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/samr34j17b.h new file mode 100644 index 000000000..4d98111d1 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/samr34j17b.h @@ -0,0 +1,637 @@ +/** + * \file + * + * \brief Header file for SAMR34J17B + * + * Copyright (c) 2017 Microchip Technology Inc. + * + * \asf_license_start + * + * \page License + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the Licence at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * \asf_license_stop + * + */ + +#ifndef _SAMR34J17B_ +#define _SAMR34J17B_ + +/** + * \ingroup SAMR34_definitions + * \addtogroup SAMR34J17B_definitions SAMR34J17B definitions + * This file defines all structures and symbols for SAMR34J17B: + * - registers and bitfields + * - peripheral base address + * - peripheral ID + * - PIO definitions +*/ +/*@{*/ + +#ifdef __cplusplus + extern "C" { +#endif + +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +#include +#ifndef __cplusplus +typedef volatile const uint32_t RoReg; /**< Read only 32-bit register (volatile const unsigned int) */ +typedef volatile const uint16_t RoReg16; /**< Read only 16-bit register (volatile const unsigned int) */ +typedef volatile const uint8_t RoReg8; /**< Read only 8-bit register (volatile const unsigned int) */ +#else +typedef volatile uint32_t RoReg; /**< Read only 32-bit register (volatile const unsigned int) */ +typedef volatile uint16_t RoReg16; /**< Read only 16-bit register (volatile const unsigned int) */ +typedef volatile uint8_t RoReg8; /**< Read only 8-bit register (volatile const unsigned int) */ +#endif +typedef volatile uint32_t WoReg; /**< Write only 32-bit register (volatile unsigned int) */ +typedef volatile uint16_t WoReg16; /**< Write only 16-bit register (volatile unsigned int) */ +typedef volatile uint8_t WoReg8; /**< Write only 8-bit register (volatile unsigned int) */ +typedef volatile uint32_t RwReg; /**< Read-Write 32-bit register (volatile unsigned int) */ +typedef volatile uint16_t RwReg16; /**< Read-Write 16-bit register (volatile unsigned int) */ +typedef volatile uint8_t RwReg8; /**< Read-Write 8-bit register (volatile unsigned int) */ +#endif + +#if !defined(SKIP_INTEGER_LITERALS) +#if defined(_U_) || defined(_L_) || defined(_UL_) + #error "Integer Literals macros already defined elsewhere" +#endif + +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +/* Macros that deal with adding suffixes to integer literal constants for C/C++ */ +#define _U_(x) x ## U /**< C code: Unsigned integer literal constant value */ +#define _L_(x) x ## L /**< C code: Long integer literal constant value */ +#define _UL_(x) x ## UL /**< C code: Unsigned Long integer literal constant value */ +#else /* Assembler */ +#define _U_(x) x /**< Assembler: Unsigned integer literal constant value */ +#define _L_(x) x /**< Assembler: Long integer literal constant value */ +#define _UL_(x) x /**< Assembler: Unsigned Long integer literal constant value */ +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ +#endif /* SKIP_INTEGER_LITERALS */ + +/* ************************************************************************** */ +/** CMSIS DEFINITIONS FOR SAMR34J17B */ +/* ************************************************************************** */ +/** \defgroup SAMR34J17B_cmsis CMSIS Definitions */ +/*@{*/ + +/** Interrupt Number Definition */ +typedef enum IRQn +{ + /****** Cortex-M0+ Processor Exceptions Numbers ******************************/ + NonMaskableInt_IRQn = -14,/**< 2 Non Maskable Interrupt */ + HardFault_IRQn = -13,/**< 3 Cortex-M0+ Hard Fault Interrupt */ + SVCall_IRQn = -5, /**< 11 Cortex-M0+ SV Call Interrupt */ + PendSV_IRQn = -2, /**< 14 Cortex-M0+ Pend SV Interrupt */ + SysTick_IRQn = -1, /**< 15 Cortex-M0+ System Tick Interrupt */ + /****** SAMR34J17B-specific Interrupt Numbers ***********************/ + SYSTEM_IRQn = 0, /**< 0 SAMR34J17B System Interrupts */ + WDT_IRQn = 1, /**< 1 SAMR34J17B Watchdog Timer (WDT) */ + RTC_IRQn = 2, /**< 2 SAMR34J17B Real-Time Counter (RTC) */ + EIC_IRQn = 3, /**< 3 SAMR34J17B External Interrupt Controller (EIC) */ + NVMCTRL_IRQn = 4, /**< 4 SAMR34J17B Non-Volatile Memory Controller (NVMCTRL) */ + DMAC_IRQn = 5, /**< 5 SAMR34J17B Direct Memory Access Controller (DMAC) */ + USB_IRQn = 6, /**< 6 SAMR34J17B Universal Serial Bus (USB) */ + EVSYS_IRQn = 7, /**< 7 SAMR34J17B Event System Interface (EVSYS) */ + SERCOM0_IRQn = 8, /**< 8 SAMR34J17B Serial Communication Interface 0 (SERCOM0) */ + SERCOM1_IRQn = 9, /**< 9 SAMR34J17B Serial Communication Interface 1 (SERCOM1) */ + SERCOM2_IRQn = 10, /**< 10 SAMR34J17B Serial Communication Interface 2 (SERCOM2) */ + SERCOM3_IRQn = 11, /**< 11 SAMR34J17B Serial Communication Interface 3 (SERCOM3) */ + SERCOM4_IRQn = 12, /**< 12 SAMR34J17B Serial Communication Interface 4 (SERCOM4) */ + SERCOM5_IRQn = 13, /**< 13 SAMR34J17B Serial Communication Interface 5 (SERCOM5) */ + TCC0_IRQn = 14, /**< 14 SAMR34J17B Timer Counter Control 0 (TCC0) */ + TCC1_IRQn = 15, /**< 15 SAMR34J17B Timer Counter Control 1 (TCC1) */ + TCC2_IRQn = 16, /**< 16 SAMR34J17B Timer Counter Control 2 (TCC2) */ + TC0_IRQn = 17, /**< 17 SAMR34J17B Basic Timer Counter 0 (TC0) */ + TC1_IRQn = 18, /**< 18 SAMR34J17B Basic Timer Counter 1 (TC1) */ + TC2_IRQn = 19, /**< 19 SAMR34J17B Basic Timer Counter 2 (TC2) */ + TC3_IRQn = 20, /**< 20 SAMR34J17B Basic Timer Counter 3 (TC3) */ + TC4_IRQn = 21, /**< 21 SAMR34J17B Basic Timer Counter 4 (TC4) */ + ADC_IRQn = 22, /**< 22 SAMR34J17B Analog Digital Converter (ADC) */ + AC_IRQn = 23, /**< 23 SAMR34J17B Analog Comparators (AC) */ + DAC_IRQn = 24, /**< 24 SAMR34J17B Digital-to-Analog Converter (DAC) */ + PTC_IRQn = 25, /**< 25 SAMR34J17B Peripheral Touch Controller (PTC) */ + AES_IRQn = 26, /**< 26 SAMR34J17B Advanced Encryption Standard (AES) */ + TRNG_IRQn = 27, /**< 27 SAMR34J17B True Random Generator (TRNG) */ + + PERIPH_COUNT_IRQn = 29 /**< Number of peripheral IDs */ +} IRQn_Type; + +typedef struct _DeviceVectors +{ + /* Stack pointer */ + void* pvStack; + + /* Cortex-M handlers */ + void* pfnReset_Handler; + void* pfnNMI_Handler; + void* pfnHardFault_Handler; + void* pvReservedM12; + void* pvReservedM11; + void* pvReservedM10; + void* pvReservedM9; + void* pvReservedM8; + void* pvReservedM7; + void* pvReservedM6; + void* pfnSVC_Handler; + void* pvReservedM4; + void* pvReservedM3; + void* pfnPendSV_Handler; + void* pfnSysTick_Handler; + + /* Peripheral handlers */ + void* pfnSYSTEM_Handler; /* 0 Main Clock, 32k Oscillators Control, Oscillators Control, Peripheral Access Controller, Power Manager, Supply Controller, Trigger Allocator */ + void* pfnWDT_Handler; /* 1 Watchdog Timer */ + void* pfnRTC_Handler; /* 2 Real-Time Counter */ + void* pfnEIC_Handler; /* 3 External Interrupt Controller */ + void* pfnNVMCTRL_Handler; /* 4 Non-Volatile Memory Controller */ + void* pfnDMAC_Handler; /* 5 Direct Memory Access Controller */ + void* pfnUSB_Handler; /* 6 Universal Serial Bus */ + void* pfnEVSYS_Handler; /* 7 Event System Interface */ + void* pfnSERCOM0_Handler; /* 8 Serial Communication Interface 0 */ + void* pfnSERCOM1_Handler; /* 9 Serial Communication Interface 1 */ + void* pfnSERCOM2_Handler; /* 10 Serial Communication Interface 2 */ + void* pfnSERCOM3_Handler; /* 11 Serial Communication Interface 3 */ + void* pfnSERCOM4_Handler; /* 12 Serial Communication Interface 4 */ + void* pfnSERCOM5_Handler; /* 13 Serial Communication Interface 5 */ + void* pfnTCC0_Handler; /* 14 Timer Counter Control 0 */ + void* pfnTCC1_Handler; /* 15 Timer Counter Control 1 */ + void* pfnTCC2_Handler; /* 16 Timer Counter Control 2 */ + void* pfnTC0_Handler; /* 17 Basic Timer Counter 0 */ + void* pfnTC1_Handler; /* 18 Basic Timer Counter 1 */ + void* pfnTC2_Handler; /* 19 Basic Timer Counter 2 */ + void* pfnTC3_Handler; /* 20 Basic Timer Counter 3 */ + void* pfnTC4_Handler; /* 21 Basic Timer Counter 4 */ + void* pfnADC_Handler; /* 22 Analog Digital Converter */ + void* pfnAC_Handler; /* 23 Analog Comparators */ + void* pfnDAC_Handler; /* 24 Digital-to-Analog Converter */ + void* pfnPTC_Handler; /* 25 Peripheral Touch Controller */ + void* pfnAES_Handler; /* 26 Advanced Encryption Standard */ + void* pfnTRNG_Handler; /* 27 True Random Generator */ + void* pvReserved28; +} DeviceVectors; + +/* Cortex-M0+ processor handlers */ +void Reset_Handler ( void ); +void NMI_Handler ( void ); +void HardFault_Handler ( void ); +void SVC_Handler ( void ); +void PendSV_Handler ( void ); +void SysTick_Handler ( void ); + +/* Peripherals handlers */ +void SYSTEM_Handler ( void ); +void WDT_Handler ( void ); +void RTC_Handler ( void ); +void EIC_Handler ( void ); +void NVMCTRL_Handler ( void ); +void DMAC_Handler ( void ); +void USB_Handler ( void ); +void EVSYS_Handler ( void ); +void SERCOM0_Handler ( void ); +void SERCOM1_Handler ( void ); +void SERCOM2_Handler ( void ); +void SERCOM3_Handler ( void ); +void SERCOM4_Handler ( void ); +void SERCOM5_Handler ( void ); +void TCC0_Handler ( void ); +void TCC1_Handler ( void ); +void TCC2_Handler ( void ); +void TC0_Handler ( void ); +void TC1_Handler ( void ); +void TC2_Handler ( void ); +void TC3_Handler ( void ); +void TC4_Handler ( void ); +void ADC_Handler ( void ); +void AC_Handler ( void ); +void DAC_Handler ( void ); +void PTC_Handler ( void ); +void AES_Handler ( void ); +void TRNG_Handler ( void ); + +/* + * \brief Configuration of the Cortex-M0+ Processor and Core Peripherals + */ + +#define LITTLE_ENDIAN 1 +#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */ +#define __MPU_PRESENT 0 /*!< MPU present or not */ +#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */ +#define __VTOR_PRESENT 1 /*!< VTOR present or not */ +#define __Vendor_SysTickConfig 0 /*!< Set to 1 if different SysTick Config is used */ + +/** + * \brief CMSIS includes + */ + +#include +#if !defined DONT_USE_CMSIS_INIT +#include "system_samr34.h" +#endif /* DONT_USE_CMSIS_INIT */ + +/*@}*/ + +/* ************************************************************************** */ +/** SOFTWARE PERIPHERAL API DEFINITION FOR SAMR34J17B */ +/* ************************************************************************** */ +/** \defgroup SAMR34J17B_api Peripheral Software API */ +/*@{*/ + +#include "component/ac.h" +#include "component/adc.h" +#include "component/aes.h" +#include "component/ccl.h" +#include "component/dac.h" +#include "component/dmac.h" +#include "component/dsu.h" +#include "component/eic.h" +#include "component/evsys.h" +#include "component/gclk.h" +#include "component/mclk.h" +#include "component/mtb.h" +#include "component/nvmctrl.h" +#include "component/oscctrl.h" +#include "component/osc32kctrl.h" +#include "component/pac.h" +#include "component/pm.h" +#include "component/port.h" +#include "component/rstc.h" +#include "component/rtc.h" +#include "component/sercom.h" +#include "component/supc.h" +#include "component/tal.h" +#include "component/tc.h" +#include "component/tcc.h" +#include "component/trng.h" +#include "component/usb.h" +#include "component/wdt.h" +/*@}*/ + +/* ************************************************************************** */ +/** REGISTERS ACCESS DEFINITIONS FOR SAMR34J17B */ +/* ************************************************************************** */ +/** \defgroup SAMR34J17B_reg Registers Access Definitions */ +/*@{*/ + +#include "instance/ac.h" +#include "instance/adc.h" +#include "instance/aes.h" +#include "instance/ccl.h" +#include "instance/dac.h" +#include "instance/dmac.h" +#include "instance/dsu.h" +#include "instance/eic.h" +#include "instance/evsys.h" +#include "instance/gclk.h" +#include "instance/mclk.h" +#include "instance/mtb.h" +#include "instance/nvmctrl.h" +#include "instance/oscctrl.h" +#include "instance/osc32kctrl.h" +#include "instance/pac.h" +#include "instance/pm.h" +#include "instance/port.h" +#include "instance/rstc.h" +#include "instance/rtc.h" +#include "instance/sercom0.h" +#include "instance/sercom1.h" +#include "instance/sercom2.h" +#include "instance/sercom3.h" +#include "instance/sercom4.h" +#include "instance/sercom5.h" +#include "instance/supc.h" +#include "instance/tal.h" +#include "instance/tc0.h" +#include "instance/tc1.h" +#include "instance/tc2.h" +#include "instance/tc3.h" +#include "instance/tc4.h" +#include "instance/tcc0.h" +#include "instance/tcc1.h" +#include "instance/tcc2.h" +#include "instance/trng.h" +#include "instance/usb.h" +#include "instance/wdt.h" +/*@}*/ + +/* ************************************************************************** */ +/** PERIPHERAL ID DEFINITIONS FOR SAMR34J17B */ +/* ************************************************************************** */ +/** \defgroup SAMR34J17B_id Peripheral Ids Definitions */ +/*@{*/ + +// Peripheral instances on HPB0 bridge +#define ID_PM 0 /**< \brief Power Manager (PM) */ +#define ID_MCLK 1 /**< \brief Main Clock (MCLK) */ +#define ID_RSTC 2 /**< \brief Reset Controller (RSTC) */ +#define ID_OSCCTRL 3 /**< \brief Oscillators Control (OSCCTRL) */ +#define ID_OSC32KCTRL 4 /**< \brief 32k Oscillators Control (OSC32KCTRL) */ +#define ID_SUPC 5 /**< \brief Supply Controller (SUPC) */ +#define ID_GCLK 6 /**< \brief Generic Clock Generator (GCLK) */ +#define ID_WDT 7 /**< \brief Watchdog Timer (WDT) */ +#define ID_RTC 8 /**< \brief Real-Time Counter (RTC) */ +#define ID_EIC 9 /**< \brief External Interrupt Controller (EIC) */ +#define ID_PORT 10 /**< \brief Port Module (PORT) */ +#define ID_TAL 11 /**< \brief Trigger Allocator (TAL) */ + +// Peripheral instances on HPB1 bridge +#define ID_USB 32 /**< \brief Universal Serial Bus (USB) */ +#define ID_DSU 33 /**< \brief Device Service Unit (DSU) */ +#define ID_NVMCTRL 34 /**< \brief Non-Volatile Memory Controller (NVMCTRL) */ +#define ID_MTB 35 /**< \brief Cortex-M0+ Micro-Trace Buffer (MTB) */ + +// Peripheral instances on HPB2 bridge +#define ID_SERCOM0 64 /**< \brief Serial Communication Interface 0 (SERCOM0) */ +#define ID_SERCOM1 65 /**< \brief Serial Communication Interface 1 (SERCOM1) */ +#define ID_SERCOM2 66 /**< \brief Serial Communication Interface 2 (SERCOM2) */ +#define ID_SERCOM3 67 /**< \brief Serial Communication Interface 3 (SERCOM3) */ +#define ID_SERCOM4 68 /**< \brief Serial Communication Interface 4 (SERCOM4) */ +#define ID_TCC0 69 /**< \brief Timer Counter Control 0 (TCC0) */ +#define ID_TCC1 70 /**< \brief Timer Counter Control 1 (TCC1) */ +#define ID_TCC2 71 /**< \brief Timer Counter Control 2 (TCC2) */ +#define ID_TC0 72 /**< \brief Basic Timer Counter 0 (TC0) */ +#define ID_TC1 73 /**< \brief Basic Timer Counter 1 (TC1) */ +#define ID_TC2 74 /**< \brief Basic Timer Counter 2 (TC2) */ +#define ID_TC3 75 /**< \brief Basic Timer Counter 3 (TC3) */ +#define ID_DAC 76 /**< \brief Digital-to-Analog Converter (DAC) */ +#define ID_AES 77 /**< \brief Advanced Encryption Standard (AES) */ +#define ID_TRNG 78 /**< \brief True Random Generator (TRNG) */ + +// Peripheral instances on HPB3 bridge +#define ID_EVSYS 96 /**< \brief Event System Interface (EVSYS) */ +#define ID_SERCOM5 97 /**< \brief Serial Communication Interface 5 (SERCOM5) */ +#define ID_TC4 98 /**< \brief Basic Timer Counter 4 (TC4) */ +#define ID_ADC 99 /**< \brief Analog Digital Converter (ADC) */ +#define ID_AC 100 /**< \brief Analog Comparators (AC) */ +#define ID_PTC 101 /**< \brief Peripheral Touch Controller (PTC) */ +#define ID_CCL 103 /**< \brief Configurable Custom Logic (CCL) */ + +// Peripheral instances on HPB4 bridge +#define ID_PAC 128 /**< \brief Peripheral Access Controller (PAC) */ +#define ID_DMAC 129 /**< \brief Direct Memory Access Controller (DMAC) */ + +#define ID_PERIPH_COUNT 130 /**< \brief Max number of peripheral IDs */ +/*@}*/ + +/* ************************************************************************** */ +/** BASE ADDRESS DEFINITIONS FOR SAMR34J17B */ +/* ************************************************************************** */ +/** \defgroup SAMR34J17B_base Peripheral Base Address Definitions */ +/*@{*/ + +#if defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__) +#define AC (0x43001000) /**< \brief (AC) APB Base Address */ +#define ADC (0x43000C00) /**< \brief (ADC) APB Base Address */ +#define AES (0x42003400) /**< \brief (AES) APB Base Address */ +#define CCL (0x43001C00) /**< \brief (CCL) APB Base Address */ +#define DAC (0x42003000) /**< \brief (DAC) APB Base Address */ +#define DMAC (0x44000400) /**< \brief (DMAC) APB Base Address */ +#define DSU (0x41002000) /**< \brief (DSU) APB Base Address */ +#define EIC (0x40002400) /**< \brief (EIC) APB Base Address */ +#define EVSYS (0x43000000) /**< \brief (EVSYS) APB Base Address */ +#define GCLK (0x40001800) /**< \brief (GCLK) APB Base Address */ +#define MCLK (0x40000400) /**< \brief (MCLK) APB Base Address */ +#define MTB (0x41006000) /**< \brief (MTB) APB Base Address */ +#define NVMCTRL (0x41004000) /**< \brief (NVMCTRL) APB Base Address */ +#define NVMCTRL_CAL (0x00800000) /**< \brief (NVMCTRL) CAL Base Address */ +#define NVMCTRL_LOCKBIT (0x00802000) /**< \brief (NVMCTRL) LOCKBIT Base Address */ +#define NVMCTRL_OTP1 (0x00806000) /**< \brief (NVMCTRL) OTP1 Base Address */ +#define NVMCTRL_OTP2 (0x00806008) /**< \brief (NVMCTRL) OTP2 Base Address */ +#define NVMCTRL_OTP3 (0x00806010) /**< \brief (NVMCTRL) OTP3 Base Address */ +#define NVMCTRL_OTP4 (0x00806018) /**< \brief (NVMCTRL) OTP4 Base Address */ +#define NVMCTRL_OTP5 (0x00806020) /**< \brief (NVMCTRL) OTP5 Base Address */ +#define NVMCTRL_TEMP_LOG (0x00806030) /**< \brief (NVMCTRL) TEMP_LOG Base Address */ +#define NVMCTRL_USER (0x00804000) /**< \brief (NVMCTRL) USER Base Address */ +#define OSCCTRL (0x40000C00) /**< \brief (OSCCTRL) APB Base Address */ +#define OSC32KCTRL (0x40001000) /**< \brief (OSC32KCTRL) APB Base Address */ +#define PAC (0x44000000) /**< \brief (PAC) APB Base Address */ +#define PM (0x40000000) /**< \brief (PM) APB Base Address */ +#define PORT (0x40002800) /**< \brief (PORT) APB Base Address */ +#define PORT_IOBUS (0x60000000) /**< \brief (PORT) IOBUS Base Address */ +#define PTC (0x43001400) /**< \brief (PTC) APB Base Address */ +#define RSTC (0x40000800) /**< \brief (RSTC) APB Base Address */ +#define RTC (0x40002000) /**< \brief (RTC) APB Base Address */ +#define SERCOM0 (0x42000000) /**< \brief (SERCOM0) APB Base Address */ +#define SERCOM1 (0x42000400) /**< \brief (SERCOM1) APB Base Address */ +#define SERCOM2 (0x42000800) /**< \brief (SERCOM2) APB Base Address */ +#define SERCOM3 (0x42000C00) /**< \brief (SERCOM3) APB Base Address */ +#define SERCOM4 (0x42001000) /**< \brief (SERCOM4) APB Base Address */ +#define SERCOM5 (0x43000400) /**< \brief (SERCOM5) APB Base Address */ +#define SUPC (0x40001400) /**< \brief (SUPC) APB Base Address */ +#define TAL (0x40002C00) /**< \brief (TAL) APB Base Address */ +#define TC0 (0x42002000) /**< \brief (TC0) APB Base Address */ +#define TC1 (0x42002400) /**< \brief (TC1) APB Base Address */ +#define TC2 (0x42002800) /**< \brief (TC2) APB Base Address */ +#define TC3 (0x42002C00) /**< \brief (TC3) APB Base Address */ +#define TC4 (0x43000800) /**< \brief (TC4) APB Base Address */ +#define TCC0 (0x42001400) /**< \brief (TCC0) APB Base Address */ +#define TCC1 (0x42001800) /**< \brief (TCC1) APB Base Address */ +#define TCC2 (0x42001C00) /**< \brief (TCC2) APB Base Address */ +#define TRNG (0x42003800) /**< \brief (TRNG) APB Base Address */ +#define USB (0x41000000) /**< \brief (USB) APB Base Address */ +#define WDT (0x40001C00) /**< \brief (WDT) APB Base Address */ +#else +#define AC ((Ac *)0x43001000UL) /**< \brief (AC) APB Base Address */ +#define AC_INST_NUM 1 /**< \brief (AC) Number of instances */ +#define AC_INSTS { AC } /**< \brief (AC) Instances List */ + +#define ADC ((Adc *)0x43000C00UL) /**< \brief (ADC) APB Base Address */ +#define ADC_INST_NUM 1 /**< \brief (ADC) Number of instances */ +#define ADC_INSTS { ADC } /**< \brief (ADC) Instances List */ + +#define AES ((Aes *)0x42003400UL) /**< \brief (AES) APB Base Address */ +#define AES_INST_NUM 1 /**< \brief (AES) Number of instances */ +#define AES_INSTS { AES } /**< \brief (AES) Instances List */ + +#define CCL ((Ccl *)0x43001C00UL) /**< \brief (CCL) APB Base Address */ +#define CCL_INST_NUM 1 /**< \brief (CCL) Number of instances */ +#define CCL_INSTS { CCL } /**< \brief (CCL) Instances List */ + +#define DAC ((Dac *)0x42003000UL) /**< \brief (DAC) APB Base Address */ +#define DAC_INST_NUM 1 /**< \brief (DAC) Number of instances */ +#define DAC_INSTS { DAC } /**< \brief (DAC) Instances List */ + +#define DMAC ((Dmac *)0x44000400UL) /**< \brief (DMAC) APB Base Address */ +#define DMAC_INST_NUM 1 /**< \brief (DMAC) Number of instances */ +#define DMAC_INSTS { DMAC } /**< \brief (DMAC) Instances List */ + +#define DSU ((Dsu *)0x41002000UL) /**< \brief (DSU) APB Base Address */ +#define DSU_INST_NUM 1 /**< \brief (DSU) Number of instances */ +#define DSU_INSTS { DSU } /**< \brief (DSU) Instances List */ + +#define EIC ((Eic *)0x40002400UL) /**< \brief (EIC) APB Base Address */ +#define EIC_INST_NUM 1 /**< \brief (EIC) Number of instances */ +#define EIC_INSTS { EIC } /**< \brief (EIC) Instances List */ + +#define EVSYS ((Evsys *)0x43000000UL) /**< \brief (EVSYS) APB Base Address */ +#define EVSYS_INST_NUM 1 /**< \brief (EVSYS) Number of instances */ +#define EVSYS_INSTS { EVSYS } /**< \brief (EVSYS) Instances List */ + +#define GCLK ((Gclk *)0x40001800UL) /**< \brief (GCLK) APB Base Address */ +#define GCLK_INST_NUM 1 /**< \brief (GCLK) Number of instances */ +#define GCLK_INSTS { GCLK } /**< \brief (GCLK) Instances List */ + +#define MCLK ((Mclk *)0x40000400UL) /**< \brief (MCLK) APB Base Address */ +#define MCLK_INST_NUM 1 /**< \brief (MCLK) Number of instances */ +#define MCLK_INSTS { MCLK } /**< \brief (MCLK) Instances List */ + +#define MTB ((Mtb *)0x41006000UL) /**< \brief (MTB) APB Base Address */ +#define MTB_INST_NUM 1 /**< \brief (MTB) Number of instances */ +#define MTB_INSTS { MTB } /**< \brief (MTB) Instances List */ + +#define NVMCTRL ((Nvmctrl *)0x41004000UL) /**< \brief (NVMCTRL) APB Base Address */ +#define NVMCTRL_CAL (0x00800000UL) /**< \brief (NVMCTRL) CAL Base Address */ +#define NVMCTRL_LOCKBIT (0x00802000UL) /**< \brief (NVMCTRL) LOCKBIT Base Address */ +#define NVMCTRL_OTP1 (0x00806000UL) /**< \brief (NVMCTRL) OTP1 Base Address */ +#define NVMCTRL_OTP2 (0x00806008UL) /**< \brief (NVMCTRL) OTP2 Base Address */ +#define NVMCTRL_OTP3 (0x00806010UL) /**< \brief (NVMCTRL) OTP3 Base Address */ +#define NVMCTRL_OTP4 (0x00806018UL) /**< \brief (NVMCTRL) OTP4 Base Address */ +#define NVMCTRL_OTP5 (0x00806020UL) /**< \brief (NVMCTRL) OTP5 Base Address */ +#define NVMCTRL_TEMP_LOG (0x00806030UL) /**< \brief (NVMCTRL) TEMP_LOG Base Address */ +#define NVMCTRL_USER (0x00804000UL) /**< \brief (NVMCTRL) USER Base Address */ +#define NVMCTRL_INST_NUM 1 /**< \brief (NVMCTRL) Number of instances */ +#define NVMCTRL_INSTS { NVMCTRL } /**< \brief (NVMCTRL) Instances List */ + +#define OSCCTRL ((Oscctrl *)0x40000C00UL) /**< \brief (OSCCTRL) APB Base Address */ +#define OSCCTRL_INST_NUM 1 /**< \brief (OSCCTRL) Number of instances */ +#define OSCCTRL_INSTS { OSCCTRL } /**< \brief (OSCCTRL) Instances List */ + +#define OSC32KCTRL ((Osc32kctrl *)0x40001000UL) /**< \brief (OSC32KCTRL) APB Base Address */ +#define OSC32KCTRL_INST_NUM 1 /**< \brief (OSC32KCTRL) Number of instances */ +#define OSC32KCTRL_INSTS { OSC32KCTRL } /**< \brief (OSC32KCTRL) Instances List */ + +#define PAC ((Pac *)0x44000000UL) /**< \brief (PAC) APB Base Address */ +#define PAC_INST_NUM 1 /**< \brief (PAC) Number of instances */ +#define PAC_INSTS { PAC } /**< \brief (PAC) Instances List */ + +#define PM ((Pm *)0x40000000UL) /**< \brief (PM) APB Base Address */ +#define PM_INST_NUM 1 /**< \brief (PM) Number of instances */ +#define PM_INSTS { PM } /**< \brief (PM) Instances List */ + +#define PORT ((Port *)0x40002800UL) /**< \brief (PORT) APB Base Address */ +#define PORT_IOBUS ((Port *)0x60000000UL) /**< \brief (PORT) IOBUS Base Address */ +#define PORT_INST_NUM 1 /**< \brief (PORT) Number of instances */ +#define PORT_INSTS { PORT } /**< \brief (PORT) Instances List */ +#define PORT_IOBUS_INST_NUM 1 /**< \brief (PORT) Number of instances */ +#define PORT_IOBUS_INSTS { PORT_IOBUS } /**< \brief (PORT) Instances List */ + +#define PTC ((void *)0x43001400UL) /**< \brief (PTC) APB Base Address */ +#define PTC_GCLK_ID 33 +#define PTC_INST_NUM 1 /**< \brief (PTC) Number of instances */ +#define PTC_INSTS { PTC } /**< \brief (PTC) Instances List */ + +#define RSTC ((Rstc *)0x40000800UL) /**< \brief (RSTC) APB Base Address */ +#define RSTC_INST_NUM 1 /**< \brief (RSTC) Number of instances */ +#define RSTC_INSTS { RSTC } /**< \brief (RSTC) Instances List */ + +#define RTC ((Rtc *)0x40002000UL) /**< \brief (RTC) APB Base Address */ +#define RTC_INST_NUM 1 /**< \brief (RTC) Number of instances */ +#define RTC_INSTS { RTC } /**< \brief (RTC) Instances List */ + +#define SERCOM0 ((Sercom *)0x42000000UL) /**< \brief (SERCOM0) APB Base Address */ +#define SERCOM1 ((Sercom *)0x42000400UL) /**< \brief (SERCOM1) APB Base Address */ +#define SERCOM2 ((Sercom *)0x42000800UL) /**< \brief (SERCOM2) APB Base Address */ +#define SERCOM3 ((Sercom *)0x42000C00UL) /**< \brief (SERCOM3) APB Base Address */ +#define SERCOM4 ((Sercom *)0x42001000UL) /**< \brief (SERCOM4) APB Base Address */ +#define SERCOM5 ((Sercom *)0x43000400UL) /**< \brief (SERCOM5) APB Base Address */ +#define SERCOM_INST_NUM 6 /**< \brief (SERCOM) Number of instances */ +#define SERCOM_INSTS { SERCOM0, SERCOM1, SERCOM2, SERCOM3, SERCOM4, SERCOM5 } /**< \brief (SERCOM) Instances List */ + +#define SUPC ((Supc *)0x40001400UL) /**< \brief (SUPC) APB Base Address */ +#define SUPC_INST_NUM 1 /**< \brief (SUPC) Number of instances */ +#define SUPC_INSTS { SUPC } /**< \brief (SUPC) Instances List */ + +#define TAL ((Tal *)0x40002C00UL) /**< \brief (TAL) APB Base Address */ +#define TAL_INST_NUM 1 /**< \brief (TAL) Number of instances */ +#define TAL_INSTS { TAL } /**< \brief (TAL) Instances List */ + +#define TC0 ((Tc *)0x42002000UL) /**< \brief (TC0) APB Base Address */ +#define TC1 ((Tc *)0x42002400UL) /**< \brief (TC1) APB Base Address */ +#define TC2 ((Tc *)0x42002800UL) /**< \brief (TC2) APB Base Address */ +#define TC3 ((Tc *)0x42002C00UL) /**< \brief (TC3) APB Base Address */ +#define TC4 ((Tc *)0x43000800UL) /**< \brief (TC4) APB Base Address */ +#define TC_INST_NUM 5 /**< \brief (TC) Number of instances */ +#define TC_INSTS { TC0, TC1, TC2, TC3, TC4 } /**< \brief (TC) Instances List */ + +#define TCC0 ((Tcc *)0x42001400UL) /**< \brief (TCC0) APB Base Address */ +#define TCC1 ((Tcc *)0x42001800UL) /**< \brief (TCC1) APB Base Address */ +#define TCC2 ((Tcc *)0x42001C00UL) /**< \brief (TCC2) APB Base Address */ +#define TCC_INST_NUM 3 /**< \brief (TCC) Number of instances */ +#define TCC_INSTS { TCC0, TCC1, TCC2 } /**< \brief (TCC) Instances List */ + +#define TRNG ((Trng *)0x42003800UL) /**< \brief (TRNG) APB Base Address */ +#define TRNG_INST_NUM 1 /**< \brief (TRNG) Number of instances */ +#define TRNG_INSTS { TRNG } /**< \brief (TRNG) Instances List */ + +#define USB ((Usb *)0x41000000UL) /**< \brief (USB) APB Base Address */ +#define USB_INST_NUM 1 /**< \brief (USB) Number of instances */ +#define USB_INSTS { USB } /**< \brief (USB) Instances List */ + +#define WDT ((Wdt *)0x40001C00UL) /**< \brief (WDT) APB Base Address */ +#define WDT_INST_NUM 1 /**< \brief (WDT) Number of instances */ +#define WDT_INSTS { WDT } /**< \brief (WDT) Instances List */ + +#endif /* (defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ +/*@}*/ + +/* ************************************************************************** */ +/** PORT DEFINITIONS FOR SAMR34J17B */ +/* ************************************************************************** */ +/** \defgroup SAMR34J17B_port PORT Definitions */ +/*@{*/ + +#include "pio/samr34j17b.h" +/*@}*/ + +/* ************************************************************************** */ +/** MEMORY MAPPING DEFINITIONS FOR SAMR34J17B */ +/* ************************************************************************** */ + +#define FLASH_SIZE _UL_(0x00020000) /* 128 kB */ +#define FLASH_PAGE_SIZE 64 +#define FLASH_NB_OF_PAGES 2048 +#define FLASH_USER_PAGE_SIZE 64 +#define HSRAM_SIZE _UL_(0x00004000) /* 16 kB */ +#define LPRAM_SIZE _UL_(0x00002000) /* 8 kB */ + +#define FLASH_ADDR _UL_(0x00000000) /**< FLASH base address */ +#define FLASH_USER_PAGE_ADDR _UL_(0x00800000) /**< FLASH_USER_PAGE base address */ +#define HSRAM_ADDR _UL_(0x20000000) /**< HSRAM base address */ +#define LPRAM_ADDR _UL_(0x30000000) /**< LPRAM base address */ +#define HPB0_ADDR _UL_(0x40000000) /**< HPB0 base address */ +#define HPB1_ADDR _UL_(0x41000000) /**< HPB1 base address */ +#define HPB2_ADDR _UL_(0x42000000) /**< HPB2 base address */ +#define HPB3_ADDR _UL_(0x43000000) /**< HPB3 base address */ +#define HPB4_ADDR _UL_(0x44000000) /**< HPB4 base address */ +#define PPB_ADDR _UL_(0xE0000000) /**< PPB base address */ + +#define DSU_DID_RESETVALUE _UL_(0x10810229) +#define NVMCTRL_RWW_EEPROM_SIZE _UL_(0x00001000) /* 4 kB */ +#define PORT_GROUPS 3 +#define SIP_CONFIG SX1276 +#define USB_HOST_IMPLEMENTED 1 + +/* ************************************************************************** */ +/** ELECTRICAL DEFINITIONS FOR SAMR34J17B */ +/* ************************************************************************** */ + + +#ifdef __cplusplus +} +#endif + +/*@}*/ + +#endif /* SAMR34J17B_H */ diff --git a/src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/samr34j18b.h b/src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/samr34j18b.h new file mode 100644 index 000000000..00b2af4b8 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/include/samr34j18b.h @@ -0,0 +1,637 @@ +/** + * \file + * + * \brief Header file for SAMR34J18B + * + * Copyright (c) 2017 Microchip Technology Inc. + * + * \asf_license_start + * + * \page License + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the Licence at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * \asf_license_stop + * + */ + +#ifndef _SAMR34J18B_ +#define _SAMR34J18B_ + +/** + * \ingroup SAMR34_definitions + * \addtogroup SAMR34J18B_definitions SAMR34J18B definitions + * This file defines all structures and symbols for SAMR34J18B: + * - registers and bitfields + * - peripheral base address + * - peripheral ID + * - PIO definitions +*/ +/*@{*/ + +#ifdef __cplusplus + extern "C" { +#endif + +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +#include +#ifndef __cplusplus +typedef volatile const uint32_t RoReg; /**< Read only 32-bit register (volatile const unsigned int) */ +typedef volatile const uint16_t RoReg16; /**< Read only 16-bit register (volatile const unsigned int) */ +typedef volatile const uint8_t RoReg8; /**< Read only 8-bit register (volatile const unsigned int) */ +#else +typedef volatile uint32_t RoReg; /**< Read only 32-bit register (volatile const unsigned int) */ +typedef volatile uint16_t RoReg16; /**< Read only 16-bit register (volatile const unsigned int) */ +typedef volatile uint8_t RoReg8; /**< Read only 8-bit register (volatile const unsigned int) */ +#endif +typedef volatile uint32_t WoReg; /**< Write only 32-bit register (volatile unsigned int) */ +typedef volatile uint16_t WoReg16; /**< Write only 16-bit register (volatile unsigned int) */ +typedef volatile uint8_t WoReg8; /**< Write only 8-bit register (volatile unsigned int) */ +typedef volatile uint32_t RwReg; /**< Read-Write 32-bit register (volatile unsigned int) */ +typedef volatile uint16_t RwReg16; /**< Read-Write 16-bit register (volatile unsigned int) */ +typedef volatile uint8_t RwReg8; /**< Read-Write 8-bit register (volatile unsigned int) */ +#endif + +#if !defined(SKIP_INTEGER_LITERALS) +#if defined(_U_) || defined(_L_) || defined(_UL_) + #error "Integer Literals macros already defined elsewhere" +#endif + +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +/* Macros that deal with adding suffixes to integer literal constants for C/C++ */ +#define _U_(x) x ## U /**< C code: Unsigned integer literal constant value */ +#define _L_(x) x ## L /**< C code: Long integer literal constant value */ +#define _UL_(x) x ## UL /**< C code: Unsigned Long integer literal constant value */ +#else /* Assembler */ +#define _U_(x) x /**< Assembler: Unsigned integer literal constant value */ +#define _L_(x) x /**< Assembler: Long integer literal constant value */ +#define _UL_(x) x /**< Assembler: Unsigned Long integer literal constant value */ +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ +#endif /* SKIP_INTEGER_LITERALS */ + +/* ************************************************************************** */ +/** CMSIS DEFINITIONS FOR SAMR34J18B */ +/* ************************************************************************** */ +/** \defgroup SAMR34J18B_cmsis CMSIS Definitions */ +/*@{*/ + +/** Interrupt Number Definition */ +typedef enum IRQn +{ + /****** Cortex-M0+ Processor Exceptions Numbers ******************************/ + NonMaskableInt_IRQn = -14,/**< 2 Non Maskable Interrupt */ + HardFault_IRQn = -13,/**< 3 Cortex-M0+ Hard Fault Interrupt */ + SVCall_IRQn = -5, /**< 11 Cortex-M0+ SV Call Interrupt */ + PendSV_IRQn = -2, /**< 14 Cortex-M0+ Pend SV Interrupt */ + SysTick_IRQn = -1, /**< 15 Cortex-M0+ System Tick Interrupt */ + /****** SAMR34J18B-specific Interrupt Numbers ***********************/ + SYSTEM_IRQn = 0, /**< 0 SAMR34J18B System Interrupts */ + WDT_IRQn = 1, /**< 1 SAMR34J18B Watchdog Timer (WDT) */ + RTC_IRQn = 2, /**< 2 SAMR34J18B Real-Time Counter (RTC) */ + EIC_IRQn = 3, /**< 3 SAMR34J18B External Interrupt Controller (EIC) */ + NVMCTRL_IRQn = 4, /**< 4 SAMR34J18B Non-Volatile Memory Controller (NVMCTRL) */ + DMAC_IRQn = 5, /**< 5 SAMR34J18B Direct Memory Access Controller (DMAC) */ + USB_IRQn = 6, /**< 6 SAMR34J18B Universal Serial Bus (USB) */ + EVSYS_IRQn = 7, /**< 7 SAMR34J18B Event System Interface (EVSYS) */ + SERCOM0_IRQn = 8, /**< 8 SAMR34J18B Serial Communication Interface 0 (SERCOM0) */ + SERCOM1_IRQn = 9, /**< 9 SAMR34J18B Serial Communication Interface 1 (SERCOM1) */ + SERCOM2_IRQn = 10, /**< 10 SAMR34J18B Serial Communication Interface 2 (SERCOM2) */ + SERCOM3_IRQn = 11, /**< 11 SAMR34J18B Serial Communication Interface 3 (SERCOM3) */ + SERCOM4_IRQn = 12, /**< 12 SAMR34J18B Serial Communication Interface 4 (SERCOM4) */ + SERCOM5_IRQn = 13, /**< 13 SAMR34J18B Serial Communication Interface 5 (SERCOM5) */ + TCC0_IRQn = 14, /**< 14 SAMR34J18B Timer Counter Control 0 (TCC0) */ + TCC1_IRQn = 15, /**< 15 SAMR34J18B Timer Counter Control 1 (TCC1) */ + TCC2_IRQn = 16, /**< 16 SAMR34J18B Timer Counter Control 2 (TCC2) */ + TC0_IRQn = 17, /**< 17 SAMR34J18B Basic Timer Counter 0 (TC0) */ + TC1_IRQn = 18, /**< 18 SAMR34J18B Basic Timer Counter 1 (TC1) */ + TC2_IRQn = 19, /**< 19 SAMR34J18B Basic Timer Counter 2 (TC2) */ + TC3_IRQn = 20, /**< 20 SAMR34J18B Basic Timer Counter 3 (TC3) */ + TC4_IRQn = 21, /**< 21 SAMR34J18B Basic Timer Counter 4 (TC4) */ + ADC_IRQn = 22, /**< 22 SAMR34J18B Analog Digital Converter (ADC) */ + AC_IRQn = 23, /**< 23 SAMR34J18B Analog Comparators (AC) */ + DAC_IRQn = 24, /**< 24 SAMR34J18B Digital-to-Analog Converter (DAC) */ + PTC_IRQn = 25, /**< 25 SAMR34J18B Peripheral Touch Controller (PTC) */ + AES_IRQn = 26, /**< 26 SAMR34J18B Advanced Encryption Standard (AES) */ + TRNG_IRQn = 27, /**< 27 SAMR34J18B True Random Generator (TRNG) */ + + PERIPH_COUNT_IRQn = 29 /**< Number of peripheral IDs */ +} IRQn_Type; + +typedef struct _DeviceVectors +{ + /* Stack pointer */ + void* pvStack; + + /* Cortex-M handlers */ + void* pfnReset_Handler; + void* pfnNMI_Handler; + void* pfnHardFault_Handler; + void* pvReservedM12; + void* pvReservedM11; + void* pvReservedM10; + void* pvReservedM9; + void* pvReservedM8; + void* pvReservedM7; + void* pvReservedM6; + void* pfnSVC_Handler; + void* pvReservedM4; + void* pvReservedM3; + void* pfnPendSV_Handler; + void* pfnSysTick_Handler; + + /* Peripheral handlers */ + void* pfnSYSTEM_Handler; /* 0 Main Clock, 32k Oscillators Control, Oscillators Control, Peripheral Access Controller, Power Manager, Supply Controller, Trigger Allocator */ + void* pfnWDT_Handler; /* 1 Watchdog Timer */ + void* pfnRTC_Handler; /* 2 Real-Time Counter */ + void* pfnEIC_Handler; /* 3 External Interrupt Controller */ + void* pfnNVMCTRL_Handler; /* 4 Non-Volatile Memory Controller */ + void* pfnDMAC_Handler; /* 5 Direct Memory Access Controller */ + void* pfnUSB_Handler; /* 6 Universal Serial Bus */ + void* pfnEVSYS_Handler; /* 7 Event System Interface */ + void* pfnSERCOM0_Handler; /* 8 Serial Communication Interface 0 */ + void* pfnSERCOM1_Handler; /* 9 Serial Communication Interface 1 */ + void* pfnSERCOM2_Handler; /* 10 Serial Communication Interface 2 */ + void* pfnSERCOM3_Handler; /* 11 Serial Communication Interface 3 */ + void* pfnSERCOM4_Handler; /* 12 Serial Communication Interface 4 */ + void* pfnSERCOM5_Handler; /* 13 Serial Communication Interface 5 */ + void* pfnTCC0_Handler; /* 14 Timer Counter Control 0 */ + void* pfnTCC1_Handler; /* 15 Timer Counter Control 1 */ + void* pfnTCC2_Handler; /* 16 Timer Counter Control 2 */ + void* pfnTC0_Handler; /* 17 Basic Timer Counter 0 */ + void* pfnTC1_Handler; /* 18 Basic Timer Counter 1 */ + void* pfnTC2_Handler; /* 19 Basic Timer Counter 2 */ + void* pfnTC3_Handler; /* 20 Basic Timer Counter 3 */ + void* pfnTC4_Handler; /* 21 Basic Timer Counter 4 */ + void* pfnADC_Handler; /* 22 Analog Digital Converter */ + void* pfnAC_Handler; /* 23 Analog Comparators */ + void* pfnDAC_Handler; /* 24 Digital-to-Analog Converter */ + void* pfnPTC_Handler; /* 25 Peripheral Touch Controller */ + void* pfnAES_Handler; /* 26 Advanced Encryption Standard */ + void* pfnTRNG_Handler; /* 27 True Random Generator */ + void* pvReserved28; +} DeviceVectors; + +/* Cortex-M0+ processor handlers */ +void Reset_Handler ( void ); +void NMI_Handler ( void ); +void HardFault_Handler ( void ); +void SVC_Handler ( void ); +void PendSV_Handler ( void ); +void SysTick_Handler ( void ); + +/* Peripherals handlers */ +void SYSTEM_Handler ( void ); +void WDT_Handler ( void ); +void RTC_Handler ( void ); +void EIC_Handler ( void ); +void NVMCTRL_Handler ( void ); +void DMAC_Handler ( void ); +void USB_Handler ( void ); +void EVSYS_Handler ( void ); +void SERCOM0_Handler ( void ); +void SERCOM1_Handler ( void ); +void SERCOM2_Handler ( void ); +void SERCOM3_Handler ( void ); +void SERCOM4_Handler ( void ); +void SERCOM5_Handler ( void ); +void TCC0_Handler ( void ); +void TCC1_Handler ( void ); +void TCC2_Handler ( void ); +void TC0_Handler ( void ); +void TC1_Handler ( void ); +void TC2_Handler ( void ); +void TC3_Handler ( void ); +void TC4_Handler ( void ); +void ADC_Handler ( void ); +void AC_Handler ( void ); +void DAC_Handler ( void ); +void PTC_Handler ( void ); +void AES_Handler ( void ); +void TRNG_Handler ( void ); + +/* + * \brief Configuration of the Cortex-M0+ Processor and Core Peripherals + */ + +#define LITTLE_ENDIAN 1 +#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */ +#define __MPU_PRESENT 0 /*!< MPU present or not */ +#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */ +#define __VTOR_PRESENT 1 /*!< VTOR present or not */ +#define __Vendor_SysTickConfig 0 /*!< Set to 1 if different SysTick Config is used */ + +/** + * \brief CMSIS includes + */ + +#include +#if !defined DONT_USE_CMSIS_INIT +#include "system_samr34.h" +#endif /* DONT_USE_CMSIS_INIT */ + +/*@}*/ + +/* ************************************************************************** */ +/** SOFTWARE PERIPHERAL API DEFINITION FOR SAMR34J18B */ +/* ************************************************************************** */ +/** \defgroup SAMR34J18B_api Peripheral Software API */ +/*@{*/ + +#include "component/ac.h" +#include "component/adc.h" +#include "component/aes.h" +#include "component/ccl.h" +#include "component/dac.h" +#include "component/dmac.h" +#include "component/dsu.h" +#include "component/eic.h" +#include "component/evsys.h" +#include "component/gclk.h" +#include "component/mclk.h" +#include "component/mtb.h" +#include "component/nvmctrl.h" +#include "component/oscctrl.h" +#include "component/osc32kctrl.h" +#include "component/pac.h" +#include "component/pm.h" +#include "component/port.h" +#include "component/rstc.h" +#include "component/rtc.h" +#include "component/sercom.h" +#include "component/supc.h" +#include "component/tal.h" +#include "component/tc.h" +#include "component/tcc.h" +#include "component/trng.h" +#include "component/usb.h" +#include "component/wdt.h" +/*@}*/ + +/* ************************************************************************** */ +/** REGISTERS ACCESS DEFINITIONS FOR SAMR34J18B */ +/* ************************************************************************** */ +/** \defgroup SAMR34J18B_reg Registers Access Definitions */ +/*@{*/ + +#include "instance/ac.h" +#include "instance/adc.h" +#include "instance/aes.h" +#include "instance/ccl.h" +#include "instance/dac.h" +#include "instance/dmac.h" +#include "instance/dsu.h" +#include "instance/eic.h" +#include "instance/evsys.h" +#include "instance/gclk.h" +#include "instance/mclk.h" +#include "instance/mtb.h" +#include "instance/nvmctrl.h" +#include "instance/oscctrl.h" +#include "instance/osc32kctrl.h" +#include "instance/pac.h" +#include "instance/pm.h" +#include "instance/port.h" +#include "instance/rstc.h" +#include "instance/rtc.h" +#include "instance/sercom0.h" +#include "instance/sercom1.h" +#include "instance/sercom2.h" +#include "instance/sercom3.h" +#include "instance/sercom4.h" +#include "instance/sercom5.h" +#include "instance/supc.h" +#include "instance/tal.h" +#include "instance/tc0.h" +#include "instance/tc1.h" +#include "instance/tc2.h" +#include "instance/tc3.h" +#include "instance/tc4.h" +#include "instance/tcc0.h" +#include "instance/tcc1.h" +#include "instance/tcc2.h" +#include "instance/trng.h" +#include "instance/usb.h" +#include "instance/wdt.h" +/*@}*/ + +/* ************************************************************************** */ +/** PERIPHERAL ID DEFINITIONS FOR SAMR34J18B */ +/* ************************************************************************** */ +/** \defgroup SAMR34J18B_id Peripheral Ids Definitions */ +/*@{*/ + +// Peripheral instances on HPB0 bridge +#define ID_PM 0 /**< \brief Power Manager (PM) */ +#define ID_MCLK 1 /**< \brief Main Clock (MCLK) */ +#define ID_RSTC 2 /**< \brief Reset Controller (RSTC) */ +#define ID_OSCCTRL 3 /**< \brief Oscillators Control (OSCCTRL) */ +#define ID_OSC32KCTRL 4 /**< \brief 32k Oscillators Control (OSC32KCTRL) */ +#define ID_SUPC 5 /**< \brief Supply Controller (SUPC) */ +#define ID_GCLK 6 /**< \brief Generic Clock Generator (GCLK) */ +#define ID_WDT 7 /**< \brief Watchdog Timer (WDT) */ +#define ID_RTC 8 /**< \brief Real-Time Counter (RTC) */ +#define ID_EIC 9 /**< \brief External Interrupt Controller (EIC) */ +#define ID_PORT 10 /**< \brief Port Module (PORT) */ +#define ID_TAL 11 /**< \brief Trigger Allocator (TAL) */ + +// Peripheral instances on HPB1 bridge +#define ID_USB 32 /**< \brief Universal Serial Bus (USB) */ +#define ID_DSU 33 /**< \brief Device Service Unit (DSU) */ +#define ID_NVMCTRL 34 /**< \brief Non-Volatile Memory Controller (NVMCTRL) */ +#define ID_MTB 35 /**< \brief Cortex-M0+ Micro-Trace Buffer (MTB) */ + +// Peripheral instances on HPB2 bridge +#define ID_SERCOM0 64 /**< \brief Serial Communication Interface 0 (SERCOM0) */ +#define ID_SERCOM1 65 /**< \brief Serial Communication Interface 1 (SERCOM1) */ +#define ID_SERCOM2 66 /**< \brief Serial Communication Interface 2 (SERCOM2) */ +#define ID_SERCOM3 67 /**< \brief Serial Communication Interface 3 (SERCOM3) */ +#define ID_SERCOM4 68 /**< \brief Serial Communication Interface 4 (SERCOM4) */ +#define ID_TCC0 69 /**< \brief Timer Counter Control 0 (TCC0) */ +#define ID_TCC1 70 /**< \brief Timer Counter Control 1 (TCC1) */ +#define ID_TCC2 71 /**< \brief Timer Counter Control 2 (TCC2) */ +#define ID_TC0 72 /**< \brief Basic Timer Counter 0 (TC0) */ +#define ID_TC1 73 /**< \brief Basic Timer Counter 1 (TC1) */ +#define ID_TC2 74 /**< \brief Basic Timer Counter 2 (TC2) */ +#define ID_TC3 75 /**< \brief Basic Timer Counter 3 (TC3) */ +#define ID_DAC 76 /**< \brief Digital-to-Analog Converter (DAC) */ +#define ID_AES 77 /**< \brief Advanced Encryption Standard (AES) */ +#define ID_TRNG 78 /**< \brief True Random Generator (TRNG) */ + +// Peripheral instances on HPB3 bridge +#define ID_EVSYS 96 /**< \brief Event System Interface (EVSYS) */ +#define ID_SERCOM5 97 /**< \brief Serial Communication Interface 5 (SERCOM5) */ +#define ID_TC4 98 /**< \brief Basic Timer Counter 4 (TC4) */ +#define ID_ADC 99 /**< \brief Analog Digital Converter (ADC) */ +#define ID_AC 100 /**< \brief Analog Comparators (AC) */ +#define ID_PTC 101 /**< \brief Peripheral Touch Controller (PTC) */ +#define ID_CCL 103 /**< \brief Configurable Custom Logic (CCL) */ + +// Peripheral instances on HPB4 bridge +#define ID_PAC 128 /**< \brief Peripheral Access Controller (PAC) */ +#define ID_DMAC 129 /**< \brief Direct Memory Access Controller (DMAC) */ + +#define ID_PERIPH_COUNT 130 /**< \brief Max number of peripheral IDs */ +/*@}*/ + +/* ************************************************************************** */ +/** BASE ADDRESS DEFINITIONS FOR SAMR34J18B */ +/* ************************************************************************** */ +/** \defgroup SAMR34J18B_base Peripheral Base Address Definitions */ +/*@{*/ + +#if defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__) +#define AC (0x43001000) /**< \brief (AC) APB Base Address */ +#define ADC (0x43000C00) /**< \brief (ADC) APB Base Address */ +#define AES (0x42003400) /**< \brief (AES) APB Base Address */ +#define CCL (0x43001C00) /**< \brief (CCL) APB Base Address */ +#define DAC (0x42003000) /**< \brief (DAC) APB Base Address */ +#define DMAC (0x44000400) /**< \brief (DMAC) APB Base Address */ +#define DSU (0x41002000) /**< \brief (DSU) APB Base Address */ +#define EIC (0x40002400) /**< \brief (EIC) APB Base Address */ +#define EVSYS (0x43000000) /**< \brief (EVSYS) APB Base Address */ +#define GCLK (0x40001800) /**< \brief (GCLK) APB Base Address */ +#define MCLK (0x40000400) /**< \brief (MCLK) APB Base Address */ +#define MTB (0x41006000) /**< \brief (MTB) APB Base Address */ +#define NVMCTRL (0x41004000) /**< \brief (NVMCTRL) APB Base Address */ +#define NVMCTRL_CAL (0x00800000) /**< \brief (NVMCTRL) CAL Base Address */ +#define NVMCTRL_LOCKBIT (0x00802000) /**< \brief (NVMCTRL) LOCKBIT Base Address */ +#define NVMCTRL_OTP1 (0x00806000) /**< \brief (NVMCTRL) OTP1 Base Address */ +#define NVMCTRL_OTP2 (0x00806008) /**< \brief (NVMCTRL) OTP2 Base Address */ +#define NVMCTRL_OTP3 (0x00806010) /**< \brief (NVMCTRL) OTP3 Base Address */ +#define NVMCTRL_OTP4 (0x00806018) /**< \brief (NVMCTRL) OTP4 Base Address */ +#define NVMCTRL_OTP5 (0x00806020) /**< \brief (NVMCTRL) OTP5 Base Address */ +#define NVMCTRL_TEMP_LOG (0x00806030) /**< \brief (NVMCTRL) TEMP_LOG Base Address */ +#define NVMCTRL_USER (0x00804000) /**< \brief (NVMCTRL) USER Base Address */ +#define OSCCTRL (0x40000C00) /**< \brief (OSCCTRL) APB Base Address */ +#define OSC32KCTRL (0x40001000) /**< \brief (OSC32KCTRL) APB Base Address */ +#define PAC (0x44000000) /**< \brief (PAC) APB Base Address */ +#define PM (0x40000000) /**< \brief (PM) APB Base Address */ +#define PORT (0x40002800) /**< \brief (PORT) APB Base Address */ +#define PORT_IOBUS (0x60000000) /**< \brief (PORT) IOBUS Base Address */ +#define PTC (0x43001400) /**< \brief (PTC) APB Base Address */ +#define RSTC (0x40000800) /**< \brief (RSTC) APB Base Address */ +#define RTC (0x40002000) /**< \brief (RTC) APB Base Address */ +#define SERCOM0 (0x42000000) /**< \brief (SERCOM0) APB Base Address */ +#define SERCOM1 (0x42000400) /**< \brief (SERCOM1) APB Base Address */ +#define SERCOM2 (0x42000800) /**< \brief (SERCOM2) APB Base Address */ +#define SERCOM3 (0x42000C00) /**< \brief (SERCOM3) APB Base Address */ +#define SERCOM4 (0x42001000) /**< \brief (SERCOM4) APB Base Address */ +#define SERCOM5 (0x43000400) /**< \brief (SERCOM5) APB Base Address */ +#define SUPC (0x40001400) /**< \brief (SUPC) APB Base Address */ +#define TAL (0x40002C00) /**< \brief (TAL) APB Base Address */ +#define TC0 (0x42002000) /**< \brief (TC0) APB Base Address */ +#define TC1 (0x42002400) /**< \brief (TC1) APB Base Address */ +#define TC2 (0x42002800) /**< \brief (TC2) APB Base Address */ +#define TC3 (0x42002C00) /**< \brief (TC3) APB Base Address */ +#define TC4 (0x43000800) /**< \brief (TC4) APB Base Address */ +#define TCC0 (0x42001400) /**< \brief (TCC0) APB Base Address */ +#define TCC1 (0x42001800) /**< \brief (TCC1) APB Base Address */ +#define TCC2 (0x42001C00) /**< \brief (TCC2) APB Base Address */ +#define TRNG (0x42003800) /**< \brief (TRNG) APB Base Address */ +#define USB (0x41000000) /**< \brief (USB) APB Base Address */ +#define WDT (0x40001C00) /**< \brief (WDT) APB Base Address */ +#else +#define AC ((Ac *)0x43001000UL) /**< \brief (AC) APB Base Address */ +#define AC_INST_NUM 1 /**< \brief (AC) Number of instances */ +#define AC_INSTS { AC } /**< \brief (AC) Instances List */ + +#define ADC ((Adc *)0x43000C00UL) /**< \brief (ADC) APB Base Address */ +#define ADC_INST_NUM 1 /**< \brief (ADC) Number of instances */ +#define ADC_INSTS { ADC } /**< \brief (ADC) Instances List */ + +#define AES ((Aes *)0x42003400UL) /**< \brief (AES) APB Base Address */ +#define AES_INST_NUM 1 /**< \brief (AES) Number of instances */ +#define AES_INSTS { AES } /**< \brief (AES) Instances List */ + +#define CCL ((Ccl *)0x43001C00UL) /**< \brief (CCL) APB Base Address */ +#define CCL_INST_NUM 1 /**< \brief (CCL) Number of instances */ +#define CCL_INSTS { CCL } /**< \brief (CCL) Instances List */ + +#define DAC ((Dac *)0x42003000UL) /**< \brief (DAC) APB Base Address */ +#define DAC_INST_NUM 1 /**< \brief (DAC) Number of instances */ +#define DAC_INSTS { DAC } /**< \brief (DAC) Instances List */ + +#define DMAC ((Dmac *)0x44000400UL) /**< \brief (DMAC) APB Base Address */ +#define DMAC_INST_NUM 1 /**< \brief (DMAC) Number of instances */ +#define DMAC_INSTS { DMAC } /**< \brief (DMAC) Instances List */ + +#define DSU ((Dsu *)0x41002000UL) /**< \brief (DSU) APB Base Address */ +#define DSU_INST_NUM 1 /**< \brief (DSU) Number of instances */ +#define DSU_INSTS { DSU } /**< \brief (DSU) Instances List */ + +#define EIC ((Eic *)0x40002400UL) /**< \brief (EIC) APB Base Address */ +#define EIC_INST_NUM 1 /**< \brief (EIC) Number of instances */ +#define EIC_INSTS { EIC } /**< \brief (EIC) Instances List */ + +#define EVSYS ((Evsys *)0x43000000UL) /**< \brief (EVSYS) APB Base Address */ +#define EVSYS_INST_NUM 1 /**< \brief (EVSYS) Number of instances */ +#define EVSYS_INSTS { EVSYS } /**< \brief (EVSYS) Instances List */ + +#define GCLK ((Gclk *)0x40001800UL) /**< \brief (GCLK) APB Base Address */ +#define GCLK_INST_NUM 1 /**< \brief (GCLK) Number of instances */ +#define GCLK_INSTS { GCLK } /**< \brief (GCLK) Instances List */ + +#define MCLK ((Mclk *)0x40000400UL) /**< \brief (MCLK) APB Base Address */ +#define MCLK_INST_NUM 1 /**< \brief (MCLK) Number of instances */ +#define MCLK_INSTS { MCLK } /**< \brief (MCLK) Instances List */ + +#define MTB ((Mtb *)0x41006000UL) /**< \brief (MTB) APB Base Address */ +#define MTB_INST_NUM 1 /**< \brief (MTB) Number of instances */ +#define MTB_INSTS { MTB } /**< \brief (MTB) Instances List */ + +#define NVMCTRL ((Nvmctrl *)0x41004000UL) /**< \brief (NVMCTRL) APB Base Address */ +#define NVMCTRL_CAL (0x00800000UL) /**< \brief (NVMCTRL) CAL Base Address */ +#define NVMCTRL_LOCKBIT (0x00802000UL) /**< \brief (NVMCTRL) LOCKBIT Base Address */ +#define NVMCTRL_OTP1 (0x00806000UL) /**< \brief (NVMCTRL) OTP1 Base Address */ +#define NVMCTRL_OTP2 (0x00806008UL) /**< \brief (NVMCTRL) OTP2 Base Address */ +#define NVMCTRL_OTP3 (0x00806010UL) /**< \brief (NVMCTRL) OTP3 Base Address */ +#define NVMCTRL_OTP4 (0x00806018UL) /**< \brief (NVMCTRL) OTP4 Base Address */ +#define NVMCTRL_OTP5 (0x00806020UL) /**< \brief (NVMCTRL) OTP5 Base Address */ +#define NVMCTRL_TEMP_LOG (0x00806030UL) /**< \brief (NVMCTRL) TEMP_LOG Base Address */ +#define NVMCTRL_USER (0x00804000UL) /**< \brief (NVMCTRL) USER Base Address */ +#define NVMCTRL_INST_NUM 1 /**< \brief (NVMCTRL) Number of instances */ +#define NVMCTRL_INSTS { NVMCTRL } /**< \brief (NVMCTRL) Instances List */ + +#define OSCCTRL ((Oscctrl *)0x40000C00UL) /**< \brief (OSCCTRL) APB Base Address */ +#define OSCCTRL_INST_NUM 1 /**< \brief (OSCCTRL) Number of instances */ +#define OSCCTRL_INSTS { OSCCTRL } /**< \brief (OSCCTRL) Instances List */ + +#define OSC32KCTRL ((Osc32kctrl *)0x40001000UL) /**< \brief (OSC32KCTRL) APB Base Address */ +#define OSC32KCTRL_INST_NUM 1 /**< \brief (OSC32KCTRL) Number of instances */ +#define OSC32KCTRL_INSTS { OSC32KCTRL } /**< \brief (OSC32KCTRL) Instances List */ + +#define PAC ((Pac *)0x44000000UL) /**< \brief (PAC) APB Base Address */ +#define PAC_INST_NUM 1 /**< \brief (PAC) Number of instances */ +#define PAC_INSTS { PAC } /**< \brief (PAC) Instances List */ + +#define PM ((Pm *)0x40000000UL) /**< \brief (PM) APB Base Address */ +#define PM_INST_NUM 1 /**< \brief (PM) Number of instances */ +#define PM_INSTS { PM } /**< \brief (PM) Instances List */ + +#define PORT ((Port *)0x40002800UL) /**< \brief (PORT) APB Base Address */ +#define PORT_IOBUS ((Port *)0x60000000UL) /**< \brief (PORT) IOBUS Base Address */ +#define PORT_INST_NUM 1 /**< \brief (PORT) Number of instances */ +#define PORT_INSTS { PORT } /**< \brief (PORT) Instances List */ +#define PORT_IOBUS_INST_NUM 1 /**< \brief (PORT) Number of instances */ +#define PORT_IOBUS_INSTS { PORT_IOBUS } /**< \brief (PORT) Instances List */ + +#define PTC ((void *)0x43001400UL) /**< \brief (PTC) APB Base Address */ +#define PTC_GCLK_ID 33 +#define PTC_INST_NUM 1 /**< \brief (PTC) Number of instances */ +#define PTC_INSTS { PTC } /**< \brief (PTC) Instances List */ + +#define RSTC ((Rstc *)0x40000800UL) /**< \brief (RSTC) APB Base Address */ +#define RSTC_INST_NUM 1 /**< \brief (RSTC) Number of instances */ +#define RSTC_INSTS { RSTC } /**< \brief (RSTC) Instances List */ + +#define RTC ((Rtc *)0x40002000UL) /**< \brief (RTC) APB Base Address */ +#define RTC_INST_NUM 1 /**< \brief (RTC) Number of instances */ +#define RTC_INSTS { RTC } /**< \brief (RTC) Instances List */ + +#define SERCOM0 ((Sercom *)0x42000000UL) /**< \brief (SERCOM0) APB Base Address */ +#define SERCOM1 ((Sercom *)0x42000400UL) /**< \brief (SERCOM1) APB Base Address */ +#define SERCOM2 ((Sercom *)0x42000800UL) /**< \brief (SERCOM2) APB Base Address */ +#define SERCOM3 ((Sercom *)0x42000C00UL) /**< \brief (SERCOM3) APB Base Address */ +#define SERCOM4 ((Sercom *)0x42001000UL) /**< \brief (SERCOM4) APB Base Address */ +#define SERCOM5 ((Sercom *)0x43000400UL) /**< \brief (SERCOM5) APB Base Address */ +#define SERCOM_INST_NUM 6 /**< \brief (SERCOM) Number of instances */ +#define SERCOM_INSTS { SERCOM0, SERCOM1, SERCOM2, SERCOM3, SERCOM4, SERCOM5 } /**< \brief (SERCOM) Instances List */ + +#define SUPC ((Supc *)0x40001400UL) /**< \brief (SUPC) APB Base Address */ +#define SUPC_INST_NUM 1 /**< \brief (SUPC) Number of instances */ +#define SUPC_INSTS { SUPC } /**< \brief (SUPC) Instances List */ + +#define TAL ((Tal *)0x40002C00UL) /**< \brief (TAL) APB Base Address */ +#define TAL_INST_NUM 1 /**< \brief (TAL) Number of instances */ +#define TAL_INSTS { TAL } /**< \brief (TAL) Instances List */ + +#define TC0 ((Tc *)0x42002000UL) /**< \brief (TC0) APB Base Address */ +#define TC1 ((Tc *)0x42002400UL) /**< \brief (TC1) APB Base Address */ +#define TC2 ((Tc *)0x42002800UL) /**< \brief (TC2) APB Base Address */ +#define TC3 ((Tc *)0x42002C00UL) /**< \brief (TC3) APB Base Address */ +#define TC4 ((Tc *)0x43000800UL) /**< \brief (TC4) APB Base Address */ +#define TC_INST_NUM 5 /**< \brief (TC) Number of instances */ +#define TC_INSTS { TC0, TC1, TC2, TC3, TC4 } /**< \brief (TC) Instances List */ + +#define TCC0 ((Tcc *)0x42001400UL) /**< \brief (TCC0) APB Base Address */ +#define TCC1 ((Tcc *)0x42001800UL) /**< \brief (TCC1) APB Base Address */ +#define TCC2 ((Tcc *)0x42001C00UL) /**< \brief (TCC2) APB Base Address */ +#define TCC_INST_NUM 3 /**< \brief (TCC) Number of instances */ +#define TCC_INSTS { TCC0, TCC1, TCC2 } /**< \brief (TCC) Instances List */ + +#define TRNG ((Trng *)0x42003800UL) /**< \brief (TRNG) APB Base Address */ +#define TRNG_INST_NUM 1 /**< \brief (TRNG) Number of instances */ +#define TRNG_INSTS { TRNG } /**< \brief (TRNG) Instances List */ + +#define USB ((Usb *)0x41000000UL) /**< \brief (USB) APB Base Address */ +#define USB_INST_NUM 1 /**< \brief (USB) Number of instances */ +#define USB_INSTS { USB } /**< \brief (USB) Instances List */ + +#define WDT ((Wdt *)0x40001C00UL) /**< \brief (WDT) APB Base Address */ +#define WDT_INST_NUM 1 /**< \brief (WDT) Number of instances */ +#define WDT_INSTS { WDT } /**< \brief (WDT) Instances List */ + +#endif /* (defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ +/*@}*/ + +/* ************************************************************************** */ +/** PORT DEFINITIONS FOR SAMR34J18B */ +/* ************************************************************************** */ +/** \defgroup SAMR34J18B_port PORT Definitions */ +/*@{*/ + +#include "pio/samr34j18b.h" +/*@}*/ + +/* ************************************************************************** */ +/** MEMORY MAPPING DEFINITIONS FOR SAMR34J18B */ +/* ************************************************************************** */ + +#define FLASH_SIZE _UL_(0x00040000) /* 256 kB */ +#define FLASH_PAGE_SIZE 64 +#define FLASH_NB_OF_PAGES 4096 +#define FLASH_USER_PAGE_SIZE 64 +#define HSRAM_SIZE _UL_(0x00008000) /* 32 kB */ +#define LPRAM_SIZE _UL_(0x00002000) /* 8 kB */ + +#define FLASH_ADDR _UL_(0x00000000) /**< FLASH base address */ +#define FLASH_USER_PAGE_ADDR _UL_(0x00800000) /**< FLASH_USER_PAGE base address */ +#define HSRAM_ADDR _UL_(0x20000000) /**< HSRAM base address */ +#define LPRAM_ADDR _UL_(0x30000000) /**< LPRAM base address */ +#define HPB0_ADDR _UL_(0x40000000) /**< HPB0 base address */ +#define HPB1_ADDR _UL_(0x41000000) /**< HPB1 base address */ +#define HPB2_ADDR _UL_(0x42000000) /**< HPB2 base address */ +#define HPB3_ADDR _UL_(0x43000000) /**< HPB3 base address */ +#define HPB4_ADDR _UL_(0x44000000) /**< HPB4 base address */ +#define PPB_ADDR _UL_(0xE0000000) /**< PPB base address */ + +#define DSU_DID_RESETVALUE _UL_(0x10810228) +#define NVMCTRL_RWW_EEPROM_SIZE _UL_(0x00002000) /* 8 kB */ +#define PORT_GROUPS 3 +#define SIP_CONFIG SX1276 +#define USB_HOST_IMPLEMENTED 1 + +/* ************************************************************************** */ +/** ELECTRICAL DEFINITIONS FOR SAMR34J18B */ +/* ************************************************************************** */ + + +#ifdef __cplusplus +} +#endif + +/*@}*/ + +#endif /* SAMR34J18B_H */ diff --git a/src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/source/gcc/startup_samr34.c b/src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/source/gcc/startup_samr34.c new file mode 100644 index 000000000..65bd2ffac --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/source/gcc/startup_samr34.c @@ -0,0 +1,257 @@ +/** + * \file + * + * \brief gcc starttup file for SAMR34 + * + * Copyright (c) 2017 Microchip Technology Inc. + * + * \asf_license_start + * + * \page License + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the Licence at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * \asf_license_stop + * + */ + +#include "samr34.h" + +/* Initialize segments */ +extern uint32_t _sfixed; +extern uint32_t _efixed; +extern uint32_t _etext; +extern uint32_t _srelocate; +extern uint32_t _erelocate; +extern uint32_t _szero; +extern uint32_t _ezero; +extern uint32_t _sstack; +extern uint32_t _estack; + +/** \cond DOXYGEN_SHOULD_SKIP_THIS */ +int main(void); +/** \endcond */ + +void __libc_init_array(void); + +/* Default empty handler */ +void Dummy_Handler(void); + +/* Cortex-M0+ core handlers */ +void NMI_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void HardFault_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void SVC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void PendSV_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void SysTick_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); + +/* Peripherals handlers */ +void SYSTEM_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); /* MCLK, OSC32KCTRL, OSCCTRL, PAC, PM, SUPC, TAL */ +void WDT_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void RTC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void EIC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void NVMCTRL_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void DMAC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#ifdef ID_USB +void USB_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#endif +void EVSYS_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void SERCOM0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void SERCOM1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void SERCOM2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void SERCOM3_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#ifdef ID_SERCOM4 +void SERCOM4_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#endif +#ifdef ID_SERCOM5 +void SERCOM5_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#endif +void TCC0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void TCC1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void TCC2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void TC0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void TC1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#ifdef ID_TC2 +void TC2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#endif +#ifdef ID_TC3 +void TC3_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#endif +void TC4_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#ifdef ID_ADC +void ADC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#endif +#ifdef ID_AC +void AC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#endif +#ifdef ID_DAC +void DAC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#endif +#ifdef ID_PTC +void PTC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#endif +#ifdef ID_AES +void AES_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#endif +#ifdef ID_TRNG +void TRNG_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#endif + +/* Exception Table */ +__attribute__ ((section(".vectors"))) +const DeviceVectors exception_table = { + + /* Configure Initial Stack Pointer, using linker-generated symbols */ + .pvStack = (void*) (&_estack), + + .pfnReset_Handler = (void*) Reset_Handler, + .pfnNMI_Handler = (void*) NMI_Handler, + .pfnHardFault_Handler = (void*) HardFault_Handler, + .pvReservedM12 = (void*) (0UL), /* Reserved */ + .pvReservedM11 = (void*) (0UL), /* Reserved */ + .pvReservedM10 = (void*) (0UL), /* Reserved */ + .pvReservedM9 = (void*) (0UL), /* Reserved */ + .pvReservedM8 = (void*) (0UL), /* Reserved */ + .pvReservedM7 = (void*) (0UL), /* Reserved */ + .pvReservedM6 = (void*) (0UL), /* Reserved */ + .pfnSVC_Handler = (void*) SVC_Handler, + .pvReservedM4 = (void*) (0UL), /* Reserved */ + .pvReservedM3 = (void*) (0UL), /* Reserved */ + .pfnPendSV_Handler = (void*) PendSV_Handler, + .pfnSysTick_Handler = (void*) SysTick_Handler, + + /* Configurable interrupts */ + .pfnSYSTEM_Handler = (void*) SYSTEM_Handler, /* 0 Main Clock, 32k Oscillators Control, Oscillators Control, Peripheral Access Controller, Power Manager, Supply Controller, Trigger Allocator */ + .pfnWDT_Handler = (void*) WDT_Handler, /* 1 Watchdog Timer */ + .pfnRTC_Handler = (void*) RTC_Handler, /* 2 Real-Time Counter */ + .pfnEIC_Handler = (void*) EIC_Handler, /* 3 External Interrupt Controller */ + .pfnNVMCTRL_Handler = (void*) NVMCTRL_Handler, /* 4 Non-Volatile Memory Controller */ + .pfnDMAC_Handler = (void*) DMAC_Handler, /* 5 Direct Memory Access Controller */ +#ifdef ID_USB + .pfnUSB_Handler = (void*) USB_Handler, /* 6 Universal Serial Bus */ +#else + .pvReserved6 = (void*) (0UL), /* 6 Reserved */ +#endif + .pfnEVSYS_Handler = (void*) EVSYS_Handler, /* 7 Event System Interface */ + .pfnSERCOM0_Handler = (void*) SERCOM0_Handler, /* 8 Serial Communication Interface 0 */ + .pfnSERCOM1_Handler = (void*) SERCOM1_Handler, /* 9 Serial Communication Interface 1 */ + .pfnSERCOM2_Handler = (void*) SERCOM2_Handler, /* 10 Serial Communication Interface 2 */ + .pfnSERCOM3_Handler = (void*) SERCOM3_Handler, /* 11 Serial Communication Interface 3 */ +#ifdef ID_SERCOM4 + .pfnSERCOM4_Handler = (void*) SERCOM4_Handler, /* 12 Serial Communication Interface 4 */ +#else + .pvReserved12 = (void*) (0UL), /* 12 Reserved */ +#endif +#ifdef ID_SERCOM5 + .pfnSERCOM5_Handler = (void*) SERCOM5_Handler, /* 13 Serial Communication Interface 5 */ +#else + .pvReserved13 = (void*) (0UL), /* 13 Reserved */ +#endif + .pfnTCC0_Handler = (void*) TCC0_Handler, /* 14 Timer Counter Control 0 */ + .pfnTCC1_Handler = (void*) TCC1_Handler, /* 15 Timer Counter Control 1 */ + .pfnTCC2_Handler = (void*) TCC2_Handler, /* 16 Timer Counter Control 2 */ + .pfnTC0_Handler = (void*) TC0_Handler, /* 17 Basic Timer Counter 0 */ + .pfnTC1_Handler = (void*) TC1_Handler, /* 18 Basic Timer Counter 1 */ +#ifdef ID_TC2 + .pfnTC2_Handler = (void*) TC2_Handler, /* 19 Basic Timer Counter 2 */ +#else + .pvReserved19 = (void*) (0UL), /* 19 Reserved */ +#endif +#ifdef ID_TC3 + .pfnTC3_Handler = (void*) TC3_Handler, /* 20 Basic Timer Counter 3 */ +#else + .pvReserved20 = (void*) (0UL), /* 20 Reserved */ +#endif + .pfnTC4_Handler = (void*) TC4_Handler, /* 21 Basic Timer Counter 4 */ +#ifdef ID_ADC + .pfnADC_Handler = (void*) ADC_Handler, /* 22 Analog Digital Converter */ +#else + .pvReserved22 = (void*) (0UL), /* 22 Reserved */ +#endif +#ifdef ID_AC + .pfnAC_Handler = (void*) AC_Handler, /* 23 Analog Comparators */ +#else + .pvReserved23 = (void*) (0UL), /* 23 Reserved */ +#endif +#ifdef ID_DAC + .pfnDAC_Handler = (void*) DAC_Handler, /* 24 Digital-to-Analog Converter */ +#else + .pvReserved24 = (void*) (0UL), /* 24 Reserved */ +#endif +#ifdef ID_PTC + .pfnPTC_Handler = (void*) PTC_Handler, /* 25 Peripheral Touch Controller */ +#else + .pvReserved25 = (void*) (0UL), /* 25 Reserved */ +#endif +#ifdef ID_AES + .pfnAES_Handler = (void*) AES_Handler, /* 26 Advanced Encryption Standard */ +#else + .pvReserved26 = (void*) (0UL), /* 26 Reserved */ +#endif +#ifdef ID_TRNG + .pfnTRNG_Handler = (void*) TRNG_Handler, /* 27 True Random Generator */ +#else + .pvReserved27 = (void*) (0UL), /* 27 Reserved */ +#endif + .pvReserved28 = (void*) (0UL) /* 28 Reserved */ +}; + +/** + * \brief This is the code that gets called on processor reset. + * To initialize the device, and call the main() routine. + */ +void Reset_Handler(void) +{ + uint32_t *pSrc, *pDest; + + /* Initialize the relocate segment */ + pSrc = &_etext; + pDest = &_srelocate; + + if (pSrc != pDest) { + for (; pDest < &_erelocate;) { + *pDest++ = *pSrc++; + } + } + + /* Clear the zero segment */ + for (pDest = &_szero; pDest < &_ezero;) { + *pDest++ = 0; + } + + /* Set the vector table base address */ + pSrc = (uint32_t *) & _sfixed; + SCB->VTOR = ((uint32_t) pSrc & SCB_VTOR_TBLOFF_Msk); + + /* Overwriting the default value of the NVMCTRL.CTRLB.MANW bit (errata reference 13134) */ + NVMCTRL->CTRLB.bit.MANW = 1; + + /* Initialize the C library */ + __libc_init_array(); + + /* Branch to main function */ + main(); + + /* Infinite loop */ + while (1); +} + +/** + * \brief Default interrupt handler for unused IRQs. + */ +void Dummy_Handler(void) +{ + while (1) { + } +} diff --git a/src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/source/system_samr34.c b/src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/source/system_samr34.c new file mode 100644 index 000000000..0a74f5871 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/source/system_samr34.c @@ -0,0 +1,64 @@ +/** + * \file + * + * \brief Low-level initialization functions called upon chip startup. + * + * Copyright (c) 2017 Microchip Technology Inc. + * + * \asf_license_start + * + * \page License + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the Licence at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * \asf_license_stop + * + */ + +#include "samr34.h" + +/** + * Initial system clock frequency. The System RC Oscillator (RCSYS) provides + * the source for the main clock at chip startup. + */ +#define __SYSTEM_CLOCK (4000000) + +uint32_t SystemCoreClock = __SYSTEM_CLOCK;/*!< System Clock Frequency (Core Clock)*/ + +/** + * Initialize the system + * + * @brief Setup the microcontroller system. + * Initialize the System and update the SystemCoreClock variable. + */ +void SystemInit(void) +{ + // Keep the default device state after reset + SystemCoreClock = __SYSTEM_CLOCK; + return; +} + +/** + * Update SystemCoreClock variable + * + * @brief Updates the SystemCoreClock with current core Clock + * retrieved from cpu registers. + */ +void SystemCoreClockUpdate(void) +{ + // Not implemented + SystemCoreClock = __SYSTEM_CLOCK; + return; +} diff --git a/src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/source/system_samr34.h b/src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/source/system_samr34.h new file mode 100644 index 000000000..689e26281 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/utils/cmsis/samr34/source/system_samr34.h @@ -0,0 +1,48 @@ +/** + * \file + * + * \brief Low-level initialization functions called upon chip startup + * + * Copyright (c) 2017 Microchip Technology Inc. + * + * \asf_license_start + * + * \page License + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the Licence at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * \asf_license_stop + * + */ + +#ifndef _SYSTEM_SAMR34_H_INCLUDED_ +#define _SYSTEM_SAMR34_H_INCLUDED_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +extern uint32_t SystemCoreClock; /*!< System Clock Frequency (Core Clock) */ + +void SystemInit(void); +void SystemCoreClockUpdate(void); + +#ifdef __cplusplus +} +#endif + +#endif /* SYSTEM_SAMR34_H_INCLUDED */ diff --git a/src/boards/mcu/samr34/ASF/sam0/utils/compiler.h b/src/boards/mcu/samr34/ASF/sam0/utils/compiler.h new file mode 100644 index 000000000..23a643643 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/utils/compiler.h @@ -0,0 +1,1166 @@ +/** + * \file + * + * \brief Commonly used includes, types and macros. + * + * Copyright (c) 2012-2019 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#ifndef UTILS_COMPILER_H_INCLUDED +#define UTILS_COMPILER_H_INCLUDED + +/** + * \defgroup group_sam0_utils Compiler abstraction layer and code utilities + * + * Compiler abstraction layer and code utilities for Cortex-M0+ based Atmel SAM devices. + * This module provides various abstraction layers and utilities to make code compatible between different compilers. + * + * @{ + */ + +#if (defined __ICCARM__) +# include +#endif + +#include +#include +#include +#include +#include + +#ifndef __ASSEMBLY__ + +#include +#include +#include +#include + +/** + * \def UNUSED + * \brief Marking \a v as a unused parameter or value. + */ +#define UNUSED(v) (void)(v) + +/** + * \def barrier + * \brief Memory barrier + */ +#ifdef __GNUC__ +# define barrier() asm volatile("" ::: "memory") +#else +# define barrier() asm ("") +#endif + +/** + * \brief Emit the compiler pragma \a arg. + * + * \param[in] arg The pragma directive as it would appear after \e \#pragma + * (i.e. not stringified). + */ +#define COMPILER_PRAGMA(arg) _Pragma(#arg) + +/** + * \def COMPILER_PACK_SET(alignment) + * \brief Set maximum alignment for subsequent struct and union definitions to \a alignment. + */ +#define COMPILER_PACK_SET(alignment) COMPILER_PRAGMA(pack(alignment)) + +/** + * \def COMPILER_PACK_RESET() + * \brief Set default alignment for subsequent struct and union definitions. + */ +#define COMPILER_PACK_RESET() COMPILER_PRAGMA(pack()) + + +/** + * \brief Set aligned boundary. + */ +#if (defined __GNUC__) || (defined __CC_ARM) +# define COMPILER_ALIGNED(a) __attribute__((__aligned__(a))) +#elif (defined __ICCARM__) +# define COMPILER_ALIGNED(a) COMPILER_PRAGMA(data_alignment = a) +#endif + +/** + * \brief Set word-aligned boundary. + */ +#if (defined __GNUC__) || defined(__CC_ARM) +#define COMPILER_WORD_ALIGNED __attribute__((__aligned__(4))) +#elif (defined __ICCARM__) +#define COMPILER_WORD_ALIGNED COMPILER_PRAGMA(data_alignment = 4) +#endif + +/** + * \def __always_inline + * \brief The function should always be inlined. + * + * This annotation instructs the compiler to ignore its inlining + * heuristics and inline the function no matter how big it thinks it + * becomes. + */ +#if defined(__CC_ARM) +# define __always_inline __forceinline +#elif (defined __GNUC__) +# define __always_inline __inline__ __attribute__((__always_inline__)) +#elif (defined __ICCARM__) +# define __always_inline _Pragma("inline=forced") +#endif + +/** + * \def __no_inline + * \brief The function should never be inlined + * + * This annotation instructs the compiler to ignore its inlining + * heuristics and not inline the function no matter how small it thinks it + * becomes. + */ +#if defined(__CC_ARM) +# define __no_inline __attribute__((noinline)) +#elif (defined __GNUC__) +# define __no_inline __attribute__((noinline)) +#elif (defined __ICCARM__) +# define __no_inline _Pragma("inline=never") +#endif + + +/** \brief This macro is used to test fatal errors. + * + * The macro tests if the expression is false. If it is, a fatal error is + * detected and the application hangs up. If \c TEST_SUITE_DEFINE_ASSERT_MACRO + * is defined, a unit test version of the macro is used, to allow execution + * of further tests after a false expression. + * + * \param[in] expr Expression to evaluate and supposed to be nonzero. + */ +#if defined(_ASSERT_ENABLE_) +# if defined(TEST_SUITE_DEFINE_ASSERT_MACRO) +# include "unit_test/suite.h" +# else +# undef TEST_SUITE_DEFINE_ASSERT_MACRO +# define Assert(expr) \ + {\ + if (!(expr)) asm("BKPT #0");\ + } +# endif +#else +# define Assert(expr) ((void) 0) +#endif + +/* Define WEAK attribute */ +#if defined ( __CC_ARM ) +# define WEAK __attribute__ ((weak)) +#elif defined ( __ICCARM__ ) +# define WEAK __weak +#elif defined ( __GNUC__ ) +# define WEAK __attribute__ ((weak)) +#endif + +/* Define NO_INIT attribute */ +#if defined ( __CC_ARM ) +# define NO_INIT __attribute__((zero_init)) +#elif defined ( __ICCARM__ ) +# define NO_INIT __no_init +#elif defined ( __GNUC__ ) +# define NO_INIT __attribute__((section(".no_init"))) +#endif + +#include "interrupt.h" + +/** \name Usual Types + * @{ */ +#ifndef __cplusplus +# if !defined(__bool_true_false_are_defined) +typedef unsigned char bool; +# endif +#endif +typedef uint16_t le16_t; +typedef uint16_t be16_t; +typedef uint32_t le32_t; +typedef uint32_t be32_t; +typedef uint32_t iram_size_t; +/** @} */ + +/** \name Aliasing Aggregate Types + * @{ */ + +/** 16-bit union. */ +typedef union +{ + int16_t s16; + uint16_t u16; + int8_t s8[2]; + uint8_t u8[2]; +} Union16; + +/** 32-bit union. */ +typedef union +{ + int32_t s32; + uint32_t u32; + int16_t s16[2]; + uint16_t u16[2]; + int8_t s8[4]; + uint8_t u8[4]; +} Union32; + +/** 64-bit union. */ +typedef union +{ + int64_t s64; + uint64_t u64; + int32_t s32[2]; + uint32_t u32[2]; + int16_t s16[4]; + uint16_t u16[4]; + int8_t s8[8]; + uint8_t u8[8]; +} Union64; + +/** Union of pointers to 64-, 32-, 16- and 8-bit unsigned integers. */ +typedef union +{ + int64_t *s64ptr; + uint64_t *u64ptr; + int32_t *s32ptr; + uint32_t *u32ptr; + int16_t *s16ptr; + uint16_t *u16ptr; + int8_t *s8ptr; + uint8_t *u8ptr; +} UnionPtr; + +/** Union of pointers to volatile 64-, 32-, 16- and 8-bit unsigned integers. */ +typedef union +{ + volatile int64_t *s64ptr; + volatile uint64_t *u64ptr; + volatile int32_t *s32ptr; + volatile uint32_t *u32ptr; + volatile int16_t *s16ptr; + volatile uint16_t *u16ptr; + volatile int8_t *s8ptr; + volatile uint8_t *u8ptr; +} UnionVPtr; + +/** Union of pointers to constant 64-, 32-, 16- and 8-bit unsigned integers. */ +typedef union +{ + const int64_t *s64ptr; + const uint64_t *u64ptr; + const int32_t *s32ptr; + const uint32_t *u32ptr; + const int16_t *s16ptr; + const uint16_t *u16ptr; + const int8_t *s8ptr; + const uint8_t *u8ptr; +} UnionCPtr; + +/** Union of pointers to constant volatile 64-, 32-, 16- and 8-bit unsigned integers. */ +typedef union +{ + const volatile int64_t *s64ptr; + const volatile uint64_t *u64ptr; + const volatile int32_t *s32ptr; + const volatile uint32_t *u32ptr; + const volatile int16_t *s16ptr; + const volatile uint16_t *u16ptr; + const volatile int8_t *s8ptr; + const volatile uint8_t *u8ptr; +} UnionCVPtr; + +/** Structure of pointers to 64-, 32-, 16- and 8-bit unsigned integers. */ +typedef struct +{ + int64_t *s64ptr; + uint64_t *u64ptr; + int32_t *s32ptr; + uint32_t *u32ptr; + int16_t *s16ptr; + uint16_t *u16ptr; + int8_t *s8ptr; + uint8_t *u8ptr; +} StructPtr; + +/** Structure of pointers to volatile 64-, 32-, 16- and 8-bit unsigned integers. */ +typedef struct +{ + volatile int64_t *s64ptr; + volatile uint64_t *u64ptr; + volatile int32_t *s32ptr; + volatile uint32_t *u32ptr; + volatile int16_t *s16ptr; + volatile uint16_t *u16ptr; + volatile int8_t *s8ptr; + volatile uint8_t *u8ptr; +} StructVPtr; + +/** Structure of pointers to constant 64-, 32-, 16- and 8-bit unsigned integers. */ +typedef struct +{ + const int64_t *s64ptr; + const uint64_t *u64ptr; + const int32_t *s32ptr; + const uint32_t *u32ptr; + const int16_t *s16ptr; + const uint16_t *u16ptr; + const int8_t *s8ptr; + const uint8_t *u8ptr; +} StructCPtr; + +/** Structure of pointers to constant volatile 64-, 32-, 16- and 8-bit unsigned integers. */ +typedef struct +{ + const volatile int64_t *s64ptr; + const volatile uint64_t *u64ptr; + const volatile int32_t *s32ptr; + const volatile uint32_t *u32ptr; + const volatile int16_t *s16ptr; + const volatile uint16_t *u16ptr; + const volatile int8_t *s8ptr; + const volatile uint8_t *u8ptr; +} StructCVPtr; + +/** @} */ + +#endif /* #ifndef __ASSEMBLY__ */ + +/** \name Usual Constants + * @{ */ +#define DISABLE 0 +#define ENABLE 1 + +#ifndef __cplusplus +# if !defined(__bool_true_false_are_defined) +# define false 0 +# define true 1 +# endif +#endif +/** @} */ + +#ifndef __ASSEMBLY__ + +/** \name Optimization Control + * @{ */ + +/** + * \def likely(exp) + * \brief The expression \a exp is likely to be true + */ +#if !defined(likely) || defined(__DOXYGEN__) +# define likely(exp) (exp) +#endif + +/** + * \def unlikely(exp) + * \brief The expression \a exp is unlikely to be true + */ +#if !defined(unlikely) || defined(__DOXYGEN__) +# define unlikely(exp) (exp) +#endif + +/** + * \def is_constant(exp) + * \brief Determine if an expression evaluates to a constant value. + * + * \param[in] exp Any expression + * + * \return true if \a exp is constant, false otherwise. + */ +#if (defined __GNUC__) || (defined __CC_ARM) +# define is_constant(exp) __builtin_constant_p(exp) +#else +# define is_constant(exp) (0) +#endif + +/** @} */ + +/** \name Bit-Field Handling + * @{ */ + +/** \brief Reads the bits of a value specified by a given bit-mask. + * + * \param[in] value Value to read bits from. + * \param[in] mask Bit-mask indicating bits to read. + * + * \return Read bits. + */ +#define Rd_bits( value, mask) ((value) & (mask)) + +/** \brief Writes the bits of a C lvalue specified by a given bit-mask. + * + * \param[in] lvalue C lvalue to write bits to. + * \param[in] mask Bit-mask indicating bits to write. + * \param[in] bits Bits to write. + * + * \return Resulting value with written bits. + */ +#define Wr_bits(lvalue, mask, bits) ((lvalue) = ((lvalue) & ~(mask)) |\ + ((bits ) & (mask))) + +/** \brief Tests the bits of a value specified by a given bit-mask. + * + * \param[in] value Value of which to test bits. + * \param[in] mask Bit-mask indicating bits to test. + * + * \return \c 1 if at least one of the tested bits is set, else \c 0. + */ +#define Tst_bits( value, mask) (Rd_bits(value, mask) != 0) + +/** \brief Clears the bits of a C lvalue specified by a given bit-mask. + * + * \param[in] lvalue C lvalue of which to clear bits. + * \param[in] mask Bit-mask indicating bits to clear. + * + * \return Resulting value with cleared bits. + */ +#define Clr_bits(lvalue, mask) ((lvalue) &= ~(mask)) + +/** \brief Sets the bits of a C lvalue specified by a given bit-mask. + * + * \param[in] lvalue C lvalue of which to set bits. + * \param[in] mask Bit-mask indicating bits to set. + * + * \return Resulting value with set bits. + */ +#define Set_bits(lvalue, mask) ((lvalue) |= (mask)) + +/** \brief Toggles the bits of a C lvalue specified by a given bit-mask. + * + * \param[in] lvalue C lvalue of which to toggle bits. + * \param[in] mask Bit-mask indicating bits to toggle. + * + * \return Resulting value with toggled bits. + */ +#define Tgl_bits(lvalue, mask) ((lvalue) ^= (mask)) + +/** \brief Reads the bit-field of a value specified by a given bit-mask. + * + * \param[in] value Value to read a bit-field from. + * \param[in] mask Bit-mask indicating the bit-field to read. + * + * \return Read bit-field. + */ +#define Rd_bitfield( value, mask) (Rd_bits( value, mask) >> ctz(mask)) + +/** \brief Writes the bit-field of a C lvalue specified by a given bit-mask. + * + * \param[in] lvalue C lvalue to write a bit-field to. + * \param[in] mask Bit-mask indicating the bit-field to write. + * \param[in] bitfield Bit-field to write. + * + * \return Resulting value with written bit-field. + */ +#define Wr_bitfield(lvalue, mask, bitfield) (Wr_bits(lvalue, mask, (uint32_t)(bitfield) << ctz(mask))) + +/** @} */ + + +/** \name Zero-Bit Counting + * + * Under GCC, __builtin_clz and __builtin_ctz behave like macros when + * applied to constant expressions (values known at compile time), so they are + * more optimized than the use of the corresponding assembly instructions and + * they can be used as constant expressions e.g. to initialize objects having + * static storage duration, and like the corresponding assembly instructions + * when applied to non-constant expressions (values unknown at compile time), so + * they are more optimized than an assembly periphrasis. Hence, clz and ctz + * ensure a possible and optimized behavior for both constant and non-constant + * expressions. + * + * @{ */ + +/** \brief Counts the leading zero bits of the given value considered as a 32-bit integer. + * + * \param[in] u Value of which to count the leading zero bits. + * + * \return The count of leading zero bits in \a u. + */ +#if (defined __GNUC__) || (defined __CC_ARM) +# define clz(u) ((u) ? __builtin_clz(u) : 32) +#else +# define clz(u) (((u) == 0) ? 32 : \ + ((u) & (1ul << 31)) ? 0 : \ + ((u) & (1ul << 30)) ? 1 : \ + ((u) & (1ul << 29)) ? 2 : \ + ((u) & (1ul << 28)) ? 3 : \ + ((u) & (1ul << 27)) ? 4 : \ + ((u) & (1ul << 26)) ? 5 : \ + ((u) & (1ul << 25)) ? 6 : \ + ((u) & (1ul << 24)) ? 7 : \ + ((u) & (1ul << 23)) ? 8 : \ + ((u) & (1ul << 22)) ? 9 : \ + ((u) & (1ul << 21)) ? 10 : \ + ((u) & (1ul << 20)) ? 11 : \ + ((u) & (1ul << 19)) ? 12 : \ + ((u) & (1ul << 18)) ? 13 : \ + ((u) & (1ul << 17)) ? 14 : \ + ((u) & (1ul << 16)) ? 15 : \ + ((u) & (1ul << 15)) ? 16 : \ + ((u) & (1ul << 14)) ? 17 : \ + ((u) & (1ul << 13)) ? 18 : \ + ((u) & (1ul << 12)) ? 19 : \ + ((u) & (1ul << 11)) ? 20 : \ + ((u) & (1ul << 10)) ? 21 : \ + ((u) & (1ul << 9)) ? 22 : \ + ((u) & (1ul << 8)) ? 23 : \ + ((u) & (1ul << 7)) ? 24 : \ + ((u) & (1ul << 6)) ? 25 : \ + ((u) & (1ul << 5)) ? 26 : \ + ((u) & (1ul << 4)) ? 27 : \ + ((u) & (1ul << 3)) ? 28 : \ + ((u) & (1ul << 2)) ? 29 : \ + ((u) & (1ul << 1)) ? 30 : \ + 31) +#endif + +/** \brief Counts the trailing zero bits of the given value considered as a 32-bit integer. + * + * \param[in] u Value of which to count the trailing zero bits. + * + * \return The count of trailing zero bits in \a u. + */ +#if (defined __GNUC__) || (defined __CC_ARM) +# define ctz(u) ((u) ? __builtin_ctz(u) : 32) +#else +# define ctz(u) ((u) & (1ul << 0) ? 0 : \ + (u) & (1ul << 1) ? 1 : \ + (u) & (1ul << 2) ? 2 : \ + (u) & (1ul << 3) ? 3 : \ + (u) & (1ul << 4) ? 4 : \ + (u) & (1ul << 5) ? 5 : \ + (u) & (1ul << 6) ? 6 : \ + (u) & (1ul << 7) ? 7 : \ + (u) & (1ul << 8) ? 8 : \ + (u) & (1ul << 9) ? 9 : \ + (u) & (1ul << 10) ? 10 : \ + (u) & (1ul << 11) ? 11 : \ + (u) & (1ul << 12) ? 12 : \ + (u) & (1ul << 13) ? 13 : \ + (u) & (1ul << 14) ? 14 : \ + (u) & (1ul << 15) ? 15 : \ + (u) & (1ul << 16) ? 16 : \ + (u) & (1ul << 17) ? 17 : \ + (u) & (1ul << 18) ? 18 : \ + (u) & (1ul << 19) ? 19 : \ + (u) & (1ul << 20) ? 20 : \ + (u) & (1ul << 21) ? 21 : \ + (u) & (1ul << 22) ? 22 : \ + (u) & (1ul << 23) ? 23 : \ + (u) & (1ul << 24) ? 24 : \ + (u) & (1ul << 25) ? 25 : \ + (u) & (1ul << 26) ? 26 : \ + (u) & (1ul << 27) ? 27 : \ + (u) & (1ul << 28) ? 28 : \ + (u) & (1ul << 29) ? 29 : \ + (u) & (1ul << 30) ? 30 : \ + (u) & (1ul << 31) ? 31 : \ + 32) +#endif + +/** @} */ + + +/** \name Bit Reversing + * @{ */ + +/** \brief Reverses the bits of \a u8. + * + * \param[in] u8 U8 of which to reverse the bits. + * + * \return Value resulting from \a u8 with reversed bits. + */ +#define bit_reverse8(u8) ((U8)(bit_reverse32((U8)(u8)) >> 24)) + +/** \brief Reverses the bits of \a u16. + * + * \param[in] u16 U16 of which to reverse the bits. + * + * \return Value resulting from \a u16 with reversed bits. + */ +#define bit_reverse16(u16) ((uint16_t)(bit_reverse32((uint16_t)(u16)) >> 16)) + +/** \brief Reverses the bits of \a u32. + * + * \param[in] u32 U32 of which to reverse the bits. + * + * \return Value resulting from \a u32 with reversed bits. + */ +#define bit_reverse32(u32) __RBIT(u32) + +/** \brief Reverses the bits of \a u64. + * + * \param[in] u64 U64 of which to reverse the bits. + * + * \return Value resulting from \a u64 with reversed bits. + */ +#define bit_reverse64(u64) ((uint64_t)(((uint64_t)bit_reverse32((uint64_t)(u64) >> 32)) |\ + ((uint64_t)bit_reverse32((uint64_t)(u64)) << 32))) + +/** @} */ + + +/** \name Alignment + * @{ */ + +/** \brief Tests alignment of the number \a val with the \a n boundary. + * + * \param[in] val Input value. + * \param[in] n Boundary. + * + * \return \c 1 if the number \a val is aligned with the \a n boundary, else \c 0. + */ +#define Test_align(val, n) (!Tst_bits( val, (n) - 1 ) ) + +/** \brief Gets alignment of the number \a val with respect to the \a n boundary. + * + * \param[in] val Input value. + * \param[in] n Boundary. + * + * \return Alignment of the number \a val with respect to the \a n boundary. + */ +#define Get_align(val, n) ( Rd_bits( val, (n) - 1 ) ) + +/** \brief Sets alignment of the lvalue number \a lval to \a alg with respect to the \a n boundary. + * + * \param[in] lval Input/output lvalue. + * \param[in] n Boundary. + * \param[in] alg Alignment. + * + * \return New value of \a lval resulting from its alignment set to \a alg with respect to the \a n boundary. + */ +#define Set_align(lval, n, alg) ( Wr_bits(lval, (n) - 1, alg) ) + +/** \brief Aligns the number \a val with the upper \a n boundary. + * + * \param[in] val Input value. + * \param[in] n Boundary. + * + * \return Value resulting from the number \a val aligned with the upper \a n boundary. + */ +#define Align_up( val, n) (((val) + ((n) - 1)) & ~((n) - 1)) + +/** \brief Aligns the number \a val with the lower \a n boundary. + * + * \param[in] val Input value. + * \param[in] n Boundary. + * + * \return Value resulting from the number \a val aligned with the lower \a n boundary. + */ +#define Align_down(val, n) ( (val) & ~((n) - 1)) + +/** @} */ + + +/** \name Mathematics + * + * The same considerations as for clz and ctz apply here but GCC does not + * provide built-in functions to access the assembly instructions abs, min and + * max and it does not produce them by itself in most cases, so two sets of + * macros are defined here: + * - Abs, Min and Max to apply to constant expressions (values known at + * compile time); + * - abs, min and max to apply to non-constant expressions (values unknown at + * compile time), abs is found in stdlib.h. + * + * @{ */ + +/** \brief Takes the absolute value of \a a. + * + * \param[in] a Input value. + * + * \return Absolute value of \a a. + * + * \note More optimized if only used with values known at compile time. + */ +#define Abs(a) (((a) < 0 ) ? -(a) : (a)) + +#ifndef __cplusplus +/** \brief Takes the minimal value of \a a and \a b. + * + * \param[in] a Input value. + * \param[in] b Input value. + * + * \return Minimal value of \a a and \a b. + * + * \note More optimized if only used with values known at compile time. + */ +#define Min(a, b) (((a) < (b)) ? (a) : (b)) + +/** \brief Takes the maximal value of \a a and \a b. + * + * \param[in] a Input value. + * \param[in] b Input value. + * + * \return Maximal value of \a a and \a b. + * + * \note More optimized if only used with values known at compile time. + */ +#define Max(a, b) (((a) > (b)) ? (a) : (b)) + +/** \brief Takes the minimal value of \a a and \a b. + * + * \param[in] a Input value. + * \param[in] b Input value. + * + * \return Minimal value of \a a and \a b. + * + * \note More optimized if only used with values unknown at compile time. + */ +#define min(a, b) Min(a, b) + +/** \brief Takes the maximal value of \a a and \a b. + * + * \param[in] a Input value. + * \param[in] b Input value. + * + * \return Maximal value of \a a and \a b. + * + * \note More optimized if only used with values unknown at compile time. + */ +#define max(a, b) Max(a, b) +#endif + +/** @} */ + + +/** \brief Calls the routine at address \a addr. + * + * It generates a long call opcode. + * + * For example, `Long_call(0x80000000)' generates a software reset on a UC3 if + * it is invoked from the CPU supervisor mode. + * + * \param[in] addr Address of the routine to call. + * + * \note It may be used as a long jump opcode in some special cases. + */ +#define Long_call(addr) ((*(void (*)(void))(addr))()) + + +/** \name MCU Endianism Handling + * ARM is MCU little endian. + * + * @{ */ +#define BE16(x) swap16(x) +#define LE16(x) (x) + +#define le16_to_cpu(x) (x) +#define cpu_to_le16(x) (x) +#define LE16_TO_CPU(x) (x) +#define CPU_TO_LE16(x) (x) + +#define be16_to_cpu(x) swap16(x) +#define cpu_to_be16(x) swap16(x) +#define BE16_TO_CPU(x) swap16(x) +#define CPU_TO_BE16(x) swap16(x) + +#define le32_to_cpu(x) (x) +#define cpu_to_le32(x) (x) +#define LE32_TO_CPU(x) (x) +#define CPU_TO_LE32(x) (x) + +#define be32_to_cpu(x) swap32(x) +#define cpu_to_be32(x) swap32(x) +#define BE32_TO_CPU(x) swap32(x) +#define CPU_TO_BE32(x) swap32(x) +/** @} */ + + +/** \name Endianism Conversion + * + * The same considerations as for clz and ctz apply here but GCC's + * __builtin_bswap_32 and __builtin_bswap_64 do not behave like macros when + * applied to constant expressions, so two sets of macros are defined here: + * - Swap16, Swap32 and Swap64 to apply to constant expressions (values known + * at compile time); + * - swap16, swap32 and swap64 to apply to non-constant expressions (values + * unknown at compile time). + * + * @{ */ + +/** \brief Toggles the endianism of \a u16 (by swapping its bytes). + * + * \param[in] u16 U16 of which to toggle the endianism. + * + * \return Value resulting from \a u16 with toggled endianism. + * + * \note More optimized if only used with values known at compile time. + */ +#define Swap16(u16) ((uint16_t)(((uint16_t)(u16) >> 8) |\ + ((uint16_t)(u16) << 8))) + +/** \brief Toggles the endianism of \a u32 (by swapping its bytes). + * + * \param[in] u32 U32 of which to toggle the endianism. + * + * \return Value resulting from \a u32 with toggled endianism. + * + * \note More optimized if only used with values known at compile time. + */ +#define Swap32(u32) ((uint32_t)(((uint32_t)Swap16((uint32_t)(u32) >> 16)) |\ + ((uint32_t)Swap16((uint32_t)(u32)) << 16))) + +/** \brief Toggles the endianism of \a u64 (by swapping its bytes). + * + * \param[in] u64 U64 of which to toggle the endianism. + * + * \return Value resulting from \a u64 with toggled endianism. + * + * \note More optimized if only used with values known at compile time. + */ +#define Swap64(u64) ((uint64_t)(((uint64_t)Swap32((uint64_t)(u64) >> 32)) |\ + ((uint64_t)Swap32((uint64_t)(u64)) << 32))) + +/** \brief Toggles the endianism of \a u16 (by swapping its bytes). + * + * \param[in] u16 U16 of which to toggle the endianism. + * + * \return Value resulting from \a u16 with toggled endianism. + * + * \note More optimized if only used with values unknown at compile time. + */ +#define swap16(u16) Swap16(u16) + +/** \brief Toggles the endianism of \a u32 (by swapping its bytes). + * + * \param[in] u32 U32 of which to toggle the endianism. + * + * \return Value resulting from \a u32 with toggled endianism. + * + * \note More optimized if only used with values unknown at compile time. + */ +#if (defined __GNUC__) +# define swap32(u32) ((uint32_t)__builtin_bswap32((uint32_t)(u32))) +#else +# define swap32(u32) Swap32(u32) +#endif + +/** \brief Toggles the endianism of \a u64 (by swapping its bytes). + * + * \param[in] u64 U64 of which to toggle the endianism. + * + * \return Value resulting from \a u64 with toggled endianism. + * + * \note More optimized if only used with values unknown at compile time. + */ +#if (defined __GNUC__) +# define swap64(u64) ((uint64_t)__builtin_bswap64((uint64_t)(u64))) +#else +# define swap64(u64) ((uint64_t)(((uint64_t)swap32((uint64_t)(u64) >> 32)) |\ + ((uint64_t)swap32((uint64_t)(u64)) << 32))) +#endif + +/** @} */ + + +/** \name Target Abstraction + * + * @{ */ + +#define _GLOBEXT_ extern /**< extern storage-class specifier. */ +#define _CONST_TYPE_ const /**< const type qualifier. */ +#define _MEM_TYPE_SLOW_ /**< Slow memory type. */ +#define _MEM_TYPE_MEDFAST_ /**< Fairly fast memory type. */ +#define _MEM_TYPE_FAST_ /**< Fast memory type. */ + +#define memcmp_ram2ram memcmp /**< Target-specific memcmp of RAM to RAM. */ +#define memcmp_code2ram memcmp /**< Target-specific memcmp of RAM to NVRAM. */ +#define memcpy_ram2ram memcpy /**< Target-specific memcpy from RAM to RAM. */ +#define memcpy_code2ram memcpy /**< Target-specific memcpy from NVRAM to RAM. */ + +/** @} */ + +/** + * \brief Calculate \f$ \left\lceil \frac{a}{b} \right\rceil \f$ using + * integer arithmetic. + * + * \param[in] a An integer + * \param[in] b Another integer + * + * \return (\a a / \a b) rounded up to the nearest integer. + */ +#define div_ceil(a, b) (((a) + (b) - 1) / (b)) + +#endif /* #ifndef __ASSEMBLY__ */ +#ifdef __ICCARM__ +/** \name Compiler Keywords + * + * Port of some keywords from GCC to IAR Embedded Workbench. + * + * @{ */ + +#define __asm__ asm +#define __inline__ inline +#define __volatile__ + +/** @} */ + +#endif + +#define FUNC_PTR void * +/** + * \def unused + * \brief Marking \a v as a unused parameter or value. + */ +#define unused(v) do { (void)(v); } while(0) + +/* Define RAMFUNC attribute */ +#if defined ( __CC_ARM ) /* Keil uVision 4 */ +# define RAMFUNC __attribute__ ((section(".ramfunc"))) +#elif defined ( __ICCARM__ ) /* IAR Ewarm 5.41+ */ +# define RAMFUNC __ramfunc +#elif defined ( __GNUC__ ) /* GCC CS3 2009q3-68 */ +# define RAMFUNC __attribute__ ((section(".ramfunc"))) +#endif + +/* Define OPTIMIZE_HIGH attribute */ +#if defined ( __CC_ARM ) /* Keil uVision 4 */ +# define OPTIMIZE_HIGH _Pragma("O3") +#elif defined ( __ICCARM__ ) /* IAR Ewarm 5.41+ */ +# define OPTIMIZE_HIGH _Pragma("optimize=high") +#elif defined ( __GNUC__ ) /* GCC CS3 2009q3-68 */ +# define OPTIMIZE_HIGH __attribute__((optimize("s"))) +#endif +#define PASS 0 +#define FAIL 1 +#define LOW 0 +#define HIGH 1 + +typedef int8_t S8 ; //!< 8-bit signed integer. +typedef uint8_t U8 ; //!< 8-bit unsigned integer. +typedef int16_t S16; //!< 16-bit signed integer. +typedef uint16_t U16; //!< 16-bit unsigned integer. +typedef int32_t S32; //!< 32-bit signed integer. +typedef uint32_t U32; //!< 32-bit unsigned integer. +typedef int64_t S64; //!< 64-bit signed integer. +typedef uint64_t U64; //!< 64-bit unsigned integer. +typedef float F32; //!< 32-bit floating-point number. +typedef double F64; //!< 64-bit floating-point number. + +#define MSB(u16) (((U8 *)&(u16))[1]) //!< Most significant byte of \a u16. +#define LSB(u16) (((U8 *)&(u16))[0]) //!< Least significant byte of \a u16. + +#define MSH(u32) (((U16 *)&(u32))[1]) //!< Most significant half-word of \a u32. +#define LSH(u32) (((U16 *)&(u32))[0]) //!< Least significant half-word of \a u32. +#define MSB0W(u32) (((U8 *)&(u32))[3]) //!< Most significant byte of 1st rank of \a u32. +#define MSB1W(u32) (((U8 *)&(u32))[2]) //!< Most significant byte of 2nd rank of \a u32. +#define MSB2W(u32) (((U8 *)&(u32))[1]) //!< Most significant byte of 3rd rank of \a u32. +#define MSB3W(u32) (((U8 *)&(u32))[0]) //!< Most significant byte of 4th rank of \a u32. +#define LSB3W(u32) MSB0W(u32) //!< Least significant byte of 4th rank of \a u32. +#define LSB2W(u32) MSB1W(u32) //!< Least significant byte of 3rd rank of \a u32. +#define LSB1W(u32) MSB2W(u32) //!< Least significant byte of 2nd rank of \a u32. +#define LSB0W(u32) MSB3W(u32) //!< Least significant byte of 1st rank of \a u32. + +#define MSW(u64) (((U32 *)&(u64))[1]) //!< Most significant word of \a u64. +#define LSW(u64) (((U32 *)&(u64))[0]) //!< Least significant word of \a u64. +#define MSH0(u64) (((U16 *)&(u64))[3]) //!< Most significant half-word of 1st rank of \a u64. +#define MSH1(u64) (((U16 *)&(u64))[2]) //!< Most significant half-word of 2nd rank of \a u64. +#define MSH2(u64) (((U16 *)&(u64))[1]) //!< Most significant half-word of 3rd rank of \a u64. +#define MSH3(u64) (((U16 *)&(u64))[0]) //!< Most significant half-word of 4th rank of \a u64. +#define LSH3(u64) MSH0(u64) //!< Least significant half-word of 4th rank of \a u64. +#define LSH2(u64) MSH1(u64) //!< Least significant half-word of 3rd rank of \a u64. +#define LSH1(u64) MSH2(u64) //!< Least significant half-word of 2nd rank of \a u64. +#define LSH0(u64) MSH3(u64) //!< Least significant half-word of 1st rank of \a u64. +#define MSB0D(u64) (((U8 *)&(u64))[7]) //!< Most significant byte of 1st rank of \a u64. +#define MSB1D(u64) (((U8 *)&(u64))[6]) //!< Most significant byte of 2nd rank of \a u64. +#define MSB2D(u64) (((U8 *)&(u64))[5]) //!< Most significant byte of 3rd rank of \a u64. +#define MSB3D(u64) (((U8 *)&(u64))[4]) //!< Most significant byte of 4th rank of \a u64. +#define MSB4D(u64) (((U8 *)&(u64))[3]) //!< Most significant byte of 5th rank of \a u64. +#define MSB5D(u64) (((U8 *)&(u64))[2]) //!< Most significant byte of 6th rank of \a u64. +#define MSB6D(u64) (((U8 *)&(u64))[1]) //!< Most significant byte of 7th rank of \a u64. +#define MSB7D(u64) (((U8 *)&(u64))[0]) //!< Most significant byte of 8th rank of \a u64. +#define LSB7D(u64) MSB0D(u64) //!< Least significant byte of 8th rank of \a u64. +#define LSB6D(u64) MSB1D(u64) //!< Least significant byte of 7th rank of \a u64. +#define LSB5D(u64) MSB2D(u64) //!< Least significant byte of 6th rank of \a u64. +#define LSB4D(u64) MSB3D(u64) //!< Least significant byte of 5th rank of \a u64. +#define LSB3D(u64) MSB4D(u64) //!< Least significant byte of 4th rank of \a u64. +#define LSB2D(u64) MSB5D(u64) //!< Least significant byte of 3rd rank of \a u64. +#define LSB1D(u64) MSB6D(u64) //!< Least significant byte of 2nd rank of \a u64. +#define LSB0D(u64) MSB7D(u64) //!< Least significant byte of 1st rank of \a u64. + +#define LSB0(u32) LSB0W(u32) //!< Least significant byte of 1st rank of \a u32. +#define LSB1(u32) LSB1W(u32) //!< Least significant byte of 2nd rank of \a u32. +#define LSB2(u32) LSB2W(u32) //!< Least significant byte of 3rd rank of \a u32. +#define LSB3(u32) LSB3W(u32) //!< Least significant byte of 4th rank of \a u32. +#define MSB3(u32) MSB3W(u32) //!< Most significant byte of 4th rank of \a u32. +#define MSB2(u32) MSB2W(u32) //!< Most significant byte of 3rd rank of \a u32. +#define MSB1(u32) MSB1W(u32) //!< Most significant byte of 2nd rank of \a u32. +#define MSB0(u32) MSB0W(u32) //!< Most significant byte of 1st rank of \a u32. + +#if defined(__ICCARM__) +#define SHORTENUM __packed +#elif defined(__GNUC__) +#define SHORTENUM __attribute__((packed)) +#endif + +/* No operation */ +#if defined(__ICCARM__) +#define nop() __no_operation() +#elif defined(__GNUC__) +#define nop() __NOP() +#endif + +#define FLASH_DECLARE(x) const x +#define FLASH_EXTERN(x) extern const x +#define PGM_READ_BYTE(x) *(x) +#define PGM_READ_WORD(x) *(x) +#define MEMCPY_ENDIAN memcpy +#define PGM_READ_BLOCK(dst, src, len) memcpy((dst), (src), (len)) + +/*Defines the Flash Storage for the request and response of MAC*/ +#define CMD_ID_OCTET (0) + +/* Converting of values from CPU endian to little endian. */ +#define CPU_ENDIAN_TO_LE16(x) (x) +#define CPU_ENDIAN_TO_LE32(x) (x) +#define CPU_ENDIAN_TO_LE64(x) (x) + +/* Converting of values from little endian to CPU endian. */ +#define LE16_TO_CPU_ENDIAN(x) (x) +#define LE32_TO_CPU_ENDIAN(x) (x) +#define LE64_TO_CPU_ENDIAN(x) (x) + +/* Converting of constants from little endian to CPU endian. */ +#define CLE16_TO_CPU_ENDIAN(x) (x) +#define CLE32_TO_CPU_ENDIAN(x) (x) +#define CLE64_TO_CPU_ENDIAN(x) (x) + +/* Converting of constants from CPU endian to little endian. */ +#define CCPU_ENDIAN_TO_LE16(x) (x) +#define CCPU_ENDIAN_TO_LE32(x) (x) +#define CCPU_ENDIAN_TO_LE64(x) (x) + +#define ADDR_COPY_DST_SRC_16(dst, src) ((dst) = (src)) +#define ADDR_COPY_DST_SRC_64(dst, src) ((dst) = (src)) + +/** + * @brief Converts a 64-Bit value into a 8 Byte array + * + * @param[in] value 64-Bit value + * @param[out] data Pointer to the 8 Byte array to be updated with 64-Bit value + * @ingroup apiPalApi + */ +static inline void convert_64_bit_to_byte_array(uint64_t value, uint8_t *data) +{ + uint8_t index = 0; + + while (index < 8) + { + data[index++] = value & 0xFF; + value = value >> 8; + } +} + +/** + * @brief Converts a 16-Bit value into a 2 Byte array + * + * @param[in] value 16-Bit value + * @param[out] data Pointer to the 2 Byte array to be updated with 16-Bit value + * @ingroup apiPalApi + */ +static inline void convert_16_bit_to_byte_array(uint16_t value, uint8_t *data) +{ + data[0] = value & 0xFF; + data[1] = (value >> 8) & 0xFF; +} + +/* Converts a 16-Bit value into a 2 Byte array */ +static inline void convert_spec_16_bit_to_byte_array(uint16_t value, uint8_t *data) +{ + data[0] = value & 0xFF; + data[1] = (value >> 8) & 0xFF; +} + +/* Converts a 16-Bit value into a 2 Byte array */ +static inline void convert_16_bit_to_byte_address(uint16_t value, uint8_t *data) +{ + data[0] = value & 0xFF; + data[1] = (value >> 8) & 0xFF; +} + +/* + * @brief Converts a 2 Byte array into a 16-Bit value + * + * @param data Specifies the pointer to the 2 Byte array + * + * @return 16-Bit value + * @ingroup apiPalApi + */ +static inline uint16_t convert_byte_array_to_16_bit(uint8_t *data) +{ + return (data[0] | ((uint16_t)data[1] << 8)); +} + +/* Converts a 4 Byte array into a 32-Bit value */ +static inline uint32_t convert_byte_array_to_32_bit(uint8_t *data) +{ + union + { + uint32_t u32; + uint8_t u8[4]; + }long_addr; + uint8_t index; + for (index = 0; index < 4; index++) + { + long_addr.u8[index] = *data++; + } + return long_addr.u32; +} + +/** + * @brief Converts a 8 Byte array into a 64-Bit value + * + * @param data Specifies the pointer to the 8 Byte array + * + * @return 64-Bit value + * @ingroup apiPalApi + */ +static inline uint64_t convert_byte_array_to_64_bit(uint8_t *data) +{ + union + { + uint64_t u64; + uint8_t u8[8]; + } long_addr; + + uint8_t index; + + for (index = 0; index < 8; index++) + { + long_addr.u8[index] = *data++; + } + + return long_addr.u64; +} + +/** @} */ + +#endif /* UTILS_COMPILER_H_INCLUDED */ diff --git a/src/boards/mcu/samr34/ASF/sam0/utils/header_files/io.h b/src/boards/mcu/samr34/ASF/sam0/utils/header_files/io.h new file mode 100644 index 000000000..4d46db5ee --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/utils/header_files/io.h @@ -0,0 +1,119 @@ +/** + * \file + * + * \brief Arch file for SAM0. + * + * This file defines common SAM0 series. + * + * Copyright (c) 2012-2020 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#ifndef _SAM_IO_ +#define _SAM_IO_ + +#include +#include +#include + +/* SAM D20 family */ +#if (SAMD20) +# include "samd20.h" +#endif + +#if (SAMD21) +# include "samd21.h" +#endif + +#if (SAMR21) +# include "samr21.h" +#endif + +#if (SAMD09) +# include "samd09.h" +#endif + +#if (SAMD10) +# include "samd10.h" +#endif + +#if (SAMD11) +# include "samd11.h" +#endif + +#if (SAML21) +# include "saml21.h" +#endif + +#if (SAMR30) +# include "samr30.h" +#endif + +#if (SAMR34) +# include "samr34.h" +#endif + +#if (WLR089) +# include "wlr089.h" +#endif + +#if (SAMR35) +# include "samr35.h" +#endif + +#if (SAML22) +# include "saml22.h" +#endif + +#if (SAMDA1) +# include "samda1.h" +#endif + +#if (SAMC20) +# include "samc20.h" +#endif + +#if (SAMC21) +# include "samc21.h" +#endif + +#if (SAMHA1) +# include "samha1.h" +#endif + +#if (SAMHA0) +# include "samha0.h" +#endif + +#if (SAMB11) +# include "samb11.h" +#endif + +#endif /* _SAM_IO_ */ diff --git a/src/boards/mcu/samr34/ASF/sam0/utils/linker_scripts/samr34/gcc/samr34j18b_flash.ld b/src/boards/mcu/samr34/ASF/sam0/utils/linker_scripts/samr34/gcc/samr34j18b_flash.ld new file mode 100644 index 000000000..5a7624294 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/utils/linker_scripts/samr34/gcc/samr34j18b_flash.ld @@ -0,0 +1,168 @@ +/** + * \file + * + * \brief Linker script for running in internal FLASH on the SAMR34J18B + * + * Copyright (c) 2015-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \asf_license_stop + * + */ + + + +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) +SEARCH_DIR(.) + +/* Memory Spaces Definitions */ +MEMORY +{ + rom (rx) : ORIGIN = 0x00000000, LENGTH = 0x00040000 + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00008000 + lpram (rwx) : ORIGIN = 0x30000000, LENGTH = 0x00002000 +} + +/* The stack size used by the application. NOTE: you need to adjust according to your application. */ +STACK_SIZE = DEFINED(STACK_SIZE) ? STACK_SIZE : DEFINED(__stack_size__) ? __stack_size__ : 0x2000; + +/* Section Definitions */ +SECTIONS +{ + .text : + { + . = ALIGN(4); + _sfixed = .; + KEEP(*(.vectors .vectors.*)) + *(.text .text.* .gnu.linkonce.t.*) + *(.glue_7t) *(.glue_7) + *(.rodata .rodata* .gnu.linkonce.r.*) + *(.ARM.extab* .gnu.linkonce.armextab.*) + + /* Support C constructors, and C destructors in both user code + and the C library. This also provides support for C++ code. */ + . = ALIGN(4); + KEEP(*(.init)) + . = ALIGN(4); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + + . = ALIGN(4); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; + + . = ALIGN(4); + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + + . = ALIGN(4); + KEEP(*(.fini)) + + . = ALIGN(4); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + __fini_array_end = .; + + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + . = ALIGN(4); + _efixed = .; /* End of text section */ + } > rom + + /* .ARM.exidx is sorted, so has to go in its own output section. */ + PROVIDE_HIDDEN (__exidx_start = .); + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > rom + PROVIDE_HIDDEN (__exidx_end = .); + + . = ALIGN(4); + _etext = .; + + .relocate : AT (_etext) + { + . = ALIGN(4); + _srelocate = .; + *(.ramfunc .ramfunc.*); + *(.data .data.*); + . = ALIGN(4); + _erelocate = .; + } > ram + + .lpram (NOLOAD): + { + . = ALIGN(8); + _slpram = .; + *(.lpram .lpram.*); + . = ALIGN(8); + _elpram = .; + } > lpram + + /* .bss section which is used for uninitialized data */ + .bss (NOLOAD) : + { + . = ALIGN(4); + _sbss = . ; + _szero = .; + *(.bss .bss.*) + *(COMMON) + . = ALIGN(4); + _ebss = . ; + _ezero = .; + } > ram + + /* stack section */ + .stack (NOLOAD): + { + . = ALIGN(8); + _sstack = .; + . = . + STACK_SIZE; + . = ALIGN(8); + _estack = .; + } > ram + + . = ALIGN(4); + _end = . ; +} diff --git a/src/boards/mcu/samr34/ASF/sam0/utils/make/Makefile.sam.in b/src/boards/mcu/samr34/ASF/sam0/utils/make/Makefile.sam.in new file mode 100644 index 000000000..dcc4cd774 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/utils/make/Makefile.sam.in @@ -0,0 +1,492 @@ +# List of available make goals: +# +# all Default target, builds the project +# clean Clean up the project +# rebuild Rebuild the project +# debug_flash Builds the project and debug in flash +# debug_sram Builds the project and debug in sram +# +# doc Build the documentation +# cleandoc Clean up the documentation +# rebuilddoc Rebuild the documentation +# +# \file +# +# Copyright (c) 2011 - 2018 Microchip Technology Inc. and its subsidiaries. +# +# \asf_license_start +# +# \page License +# +# Subject to your compliance with these terms, you may use Microchip +# software and any derivatives exclusively with Microchip products. +# It is your responsibility to comply with third party license terms applicable +# to your use of third party software (including open source software) that +# may accompany Microchip software. +# +# THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, +# WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, +# INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, +# AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE +# LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL +# LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE +# SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE +# POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT +# ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY +# RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, +# THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. +# +# \asf_license_stop +# + +# Include the config.mk file from the current working path, e.g., where the +# user called make. +include config.mk + +# Tool to use to generate documentation from the source code +DOCGEN ?= doxygen + +# Look for source files relative to the top-level source directory +VPATH := $(PRJ_PATH) + +# Output target file +project_type := $(PROJECT_TYPE) + +# Output target file +ifeq ($(project_type),flash) +target := $(TARGET_FLASH) +linker_script := $(PRJ_PATH)/$(LINKER_SCRIPT_FLASH) +debug_script := $(PRJ_PATH)/$(DEBUG_SCRIPT_FLASH) +else +target := $(TARGET_SRAM) +linker_script := $(PRJ_PATH)/$(LINKER_SCRIPT_SRAM) +debug_script := $(PRJ_PATH)/$(DEBUG_SCRIPT_SRAM) +endif + +# Output project name (target name minus suffix) +project := $(basename $(target)) + +# Output target file (typically ELF or static library) +ifeq ($(suffix $(target)),.a) +target_type := lib +else +ifeq ($(suffix $(target)),.elf) +target_type := elf +else +$(error "Target type $(target_type) is not supported") +endif +endif + +# Allow override of operating system detection. The user can add OS=Linux or +# OS=Windows on the command line to explicit set the host OS. +# +# This allows to work around broken uname utility on certain systems. +ifdef OS + ifeq ($(strip $(OS)), Linux) + os_type := Linux + endif + ifeq ($(strip $(OS)), Windows) + os_type := windows32_64 + endif +endif + +os_type ?= $(strip $(shell uname)) + +ifeq ($(os_type),windows32) +os := Windows +else +ifeq ($(os_type),windows64) +os := Windows +else +ifeq ($(os_type),windows32_64) +os ?= Windows +else +ifeq ($(os_type),) +os := Windows +else +# Default to Linux style operating system. Both Cygwin and mingw are fully +# compatible (for this Makefile) with Linux. +os := Linux +endif +endif +endif +endif + +# Output documentation directory and configuration file. +docdir := ../doxygen/html +doccfg := ../doxygen/doxyfile.doxygen + +CROSS ?= arm-none-eabi- +AR := $(CROSS)ar +AS := $(CROSS)as +CC := $(CROSS)gcc +CPP := $(CROSS)gcc -E +CXX := $(CROSS)g++ +LD := $(CROSS)g++ +NM := $(CROSS)nm +OBJCOPY := $(CROSS)objcopy +OBJDUMP := $(CROSS)objdump +SIZE := $(CROSS)size +GDB := $(CROSS)gdb + +RM := rm +ifeq ($(os),Windows) +RMDIR := rmdir /S /Q +else +RMDIR := rmdir -p --ignore-fail-on-non-empty +endif + +# On Windows, we need to override the shell to force the use of cmd.exe +ifeq ($(os),Windows) +SHELL := cmd +endif + +# Strings for beautifying output +MSG_CLEAN_FILES = "RM *.o *.d" +MSG_CLEAN_DIRS = "RMDIR $(strip $(clean-dirs))" +MSG_CLEAN_DOC = "RMDIR $(docdir)" +MSG_MKDIR = "MKDIR $(dir $@)" + +MSG_INFO = "INFO " +MSG_PREBUILD = "PREBUILD $(PREBUILD_CMD)" +MSG_POSTBUILD = "POSTBUILD $(POSTBUILD_CMD)" + +MSG_ARCHIVING = "AR $@" +MSG_ASSEMBLING = "AS $@" +MSG_BINARY_IMAGE = "OBJCOPY $@" +MSG_COMPILING = "CC $@" +MSG_COMPILING_CXX = "CXX $@" +MSG_EXTENDED_LISTING = "OBJDUMP $@" +MSG_IHEX_IMAGE = "OBJCOPY $@" +MSG_LINKING = "LN $@" +MSG_PREPROCESSING = "CPP $@" +MSG_SIZE = "SIZE $@" +MSG_SYMBOL_TABLE = "NM $@" + +MSG_GENERATING_DOC = "DOXYGEN $(docdir)" + +# Don't use make's built-in rules and variables +MAKEFLAGS += -rR + +# Don't print 'Entering directory ...' +MAKEFLAGS += --no-print-directory + +# Function for reversing the order of a list +reverse = $(if $(1),$(call reverse,$(wordlist 2,$(words $(1)),$(1)))) $(firstword $(1)) + +# Hide command output by default, but allow the user to override this +# by adding V=1 on the command line. +# +# This is inspired by the Kbuild system used by the Linux kernel. +ifdef V + ifeq ("$(origin V)", "command line") + VERBOSE = $(V) + endif +endif +ifndef VERBOSE + VERBOSE = 0 +endif + +ifeq ($(VERBOSE), 1) + Q = +else + Q = @ +endif + +arflags-gnu-y := $(ARFLAGS) +asflags-gnu-y := $(ASFLAGS) +cflags-gnu-y := $(CFLAGS) +cxxflags-gnu-y := $(CXXFLAGS) +cppflags-gnu-y := $(CPPFLAGS) +cpuflags-gnu-y := +dbgflags-gnu-y := $(DBGFLAGS) +libflags-gnu-y := $(foreach LIB,$(LIBS),-l$(LIB)) +ldflags-gnu-y := $(LDFLAGS) +flashflags-gnu-y := +clean-files := +clean-dirs := + +clean-files += $(wildcard $(target) $(project).map) +clean-files += $(wildcard $(project).hex $(project).bin) +clean-files += $(wildcard $(project).lss $(project).sym) +clean-files += $(wildcard $(build)) + +# Use pipes instead of temporary files for communication between processes +cflags-gnu-y += -pipe +asflags-gnu-y += -pipe +ldflags-gnu-y += -pipe + +# Archiver flags. +arflags-gnu-y += rcs + +# Always enable warnings. And be very careful about implicit +# declarations. +cflags-gnu-y += -Wall -Wstrict-prototypes -Wmissing-prototypes +cflags-gnu-y += -Werror-implicit-function-declaration +cxxflags-gnu-y += -Wall +# IAR doesn't allow arithmetic on void pointers, so warn about that. +cflags-gnu-y += -Wpointer-arith +cxxflags-gnu-y += -Wpointer-arith + +# Preprocessor flags. +cppflags-gnu-y += $(foreach INC,$(addprefix $(PRJ_PATH)/,$(INC_PATH)),-I$(INC)) +asflags-gnu-y += $(foreach INC,$(addprefix $(PRJ_PATH)/,$(INC_PATH)),'-Wa,-I$(INC)') + +# CPU specific flags. +cpuflags-gnu-y += -mcpu=$(ARCH) -mthumb -D=__$(PART)__ + +# Dependency file flags. +depflags = -MD -MP -MQ $@ + +# Debug specific flags. +ifdef BUILD_DEBUG_LEVEL +dbgflags-gnu-y += -g$(BUILD_DEBUG_LEVEL) +else +dbgflags-gnu-y += -g3 +endif + +# Optimization specific flags. +ifdef BUILD_OPTIMIZATION +optflags-gnu-y = -O$(BUILD_OPTIMIZATION) +else +optflags-gnu-y = $(OPTIMIZATION) +endif + +# Always preprocess assembler files. +asflags-gnu-y += -x assembler-with-cpp +# Compile C files using the GNU99 standard. +cflags-gnu-y += -std=gnu99 +# Compile C++ files using the GNU++98 standard. +cxxflags-gnu-y += -std=gnu++98 + +# Don't use strict aliasing (very common in embedded applications). +cflags-gnu-y += -fno-strict-aliasing +cxxflags-gnu-y += -fno-strict-aliasing + +# Separate each function and data into its own separate section to allow +# garbage collection of unused sections. +cflags-gnu-y += -ffunction-sections -fdata-sections +cxxflags-gnu-y += -ffunction-sections -fdata-sections + +# Various cflags. +cflags-gnu-y += -Wchar-subscripts -Wcomment -Wformat=2 -Wimplicit-int +cflags-gnu-y += -Wmain -Wparentheses +cflags-gnu-y += -Wsequence-point -Wreturn-type -Wswitch -Wtrigraphs -Wunused +cflags-gnu-y += -Wuninitialized -Wunknown-pragmas -Wfloat-equal -Wundef +cflags-gnu-y += -Wshadow -Wbad-function-cast -Wwrite-strings +cflags-gnu-y += -Wsign-compare -Waggregate-return +cflags-gnu-y += -Wmissing-declarations +cflags-gnu-y += -Wformat -Wmissing-format-attribute -Wno-deprecated-declarations +cflags-gnu-y += -Wpacked -Wredundant-decls -Wnested-externs -Wlong-long +cflags-gnu-y += -Wunreachable-code +cflags-gnu-y += -Wcast-align +cflags-gnu-y += --param max-inline-insns-single=500 + +# To reduce application size use only integer printf function. +cflags-gnu-y += -Dprintf=iprintf + +# Use newlib-nano to reduce application size +ldflags-gnu-y += --specs=nano.specs + +# Garbage collect unreferred sections when linking. +ldflags-gnu-y += -Wl,--gc-sections + +# Use the linker script if provided by the project. +ifneq ($(strip $(linker_script)),) +ldflags-gnu-y += -Wl,-T $(linker_script) +endif + +# Output a link map file and a cross reference table +ldflags-gnu-y += -Wl,-Map=$(project).map,--cref + +# Add library search paths relative to the top level directory. +ldflags-gnu-y += $(foreach _LIB_PATH,$(addprefix $(PRJ_PATH)/,$(LIB_PATH)),-L$(_LIB_PATH)) + +a_flags = $(cpuflags-gnu-y) $(depflags) $(cppflags-gnu-y) $(asflags-gnu-y) -D__ASSEMBLY__ +c_flags = $(cpuflags-gnu-y) $(dbgflags-gnu-y) $(depflags) $(optflags-gnu-y) $(cppflags-gnu-y) $(cflags-gnu-y) +cxx_flags= $(cpuflags-gnu-y) $(dbgflags-gnu-y) $(depflags) $(optflags-gnu-y) $(cppflags-gnu-y) $(cxxflags-gnu-y) +l_flags = -Wl,--entry=Reset_Handler -Wl,--cref $(cpuflags-gnu-y) $(optflags-gnu-y) $(ldflags-gnu-y) +ar_flags = $(arflags-gnu-y) + +# Source files list and part informations must already be included before +# running this makefile + +# If a custom build directory is specified, use it -- force trailing / in directory name. +ifdef BUILD_DIR + build-dir := $(dir $(BUILD_DIR))$(if $(notdir $(BUILD_DIR)),$(notdir $(BUILD_DIR))/) +else + build-dir = +endif + +# Create object files list from source files list. +obj-y := $(addprefix $(build-dir), $(addsuffix .o,$(basename $(CSRCS) $(ASSRCS)))) +# Create dependency files list from source files list. +dep-files := $(wildcard $(foreach f,$(obj-y),$(basename $(f)).d)) + +clean-files += $(wildcard $(obj-y)) +clean-files += $(dep-files) + +clean-dirs += $(call reverse,$(sort $(wildcard $(dir $(obj-y))))) + +# Default target. +.PHONY: all +ifeq ($(project_type),all) +all: + $(MAKE) all PROJECT_TYPE=flash + $(MAKE) all PROJECT_TYPE=sram +else +ifeq ($(target_type),lib) +all: $(target) $(project).lss $(project).sym +else +ifeq ($(target_type),elf) +all: prebuild $(target) $(project).lss $(project).sym $(project).hex $(project).bin postbuild +endif +endif +endif + +prebuild: +ifneq ($(strip $(PREBUILD_CMD)),) + @echo $(MSG_PREBUILD) + $(Q)$(PREBUILD_CMD) +endif + +postbuild: +ifneq ($(strip $(POSTBUILD_CMD)),) + @echo $(MSG_POSTBUILD) + $(Q)$(POSTBUILD_CMD) +endif + +# Clean up the project. +.PHONY: clean +clean: + @$(if $(strip $(clean-files)),echo $(MSG_CLEAN_FILES)) + $(if $(strip $(clean-files)),$(Q)$(RM) $(clean-files),) + @$(if $(strip $(clean-dirs)),echo $(MSG_CLEAN_DIRS)) +# Remove created directories, and make sure we only remove existing +# directories, since recursive rmdir might help us a bit on the way. +ifeq ($(os),Windows) + $(Q)$(if $(strip $(clean-dirs)), \ + $(RMDIR) $(strip $(subst /,\,$(clean-dirs)))) +else + $(Q)$(if $(strip $(clean-dirs)), \ + for directory in $(strip $(clean-dirs)); do \ + if [ -d "$$directory" ]; then \ + $(RMDIR) $$directory; \ + fi \ + done \ + ) +endif + +# Rebuild the project. +.PHONY: rebuild +rebuild: clean all + +# Debug the project in flash. +.PHONY: debug_flash +debug_flash: all + $(GDB) -x "$(PRJ_PATH)/$(DEBUG_SCRIPT_FLASH)" -ex "reset" -readnow -se $(TARGET_FLASH) + +# Debug the project in sram. +.PHONY: debug_sram +debug_sram: all + $(GDB) -x "$(PRJ_PATH)/$(DEBUG_SCRIPT_SRAM)" -ex "reset" -readnow -se $(TARGET_SRAM) + +.PHONY: objfiles +objfiles: $(obj-y) + +# Create object files from C source files. +$(build-dir)%.o: %.c $(MAKEFILE_PATH) config.mk + $(Q)test -d $(dir $@) || echo $(MSG_MKDIR) +ifeq ($(os),Windows) + $(Q)test -d $(patsubst %/,%,$(dir $@)) || mkdir $(subst /,\,$(dir $@)) +else + $(Q)test -d $(dir $@) || mkdir -p $(dir $@) +endif + @echo $(MSG_COMPILING) + $(Q)$(CC) $(c_flags) -c $< -o $@ + +# Create object files from C++ source files. +$(build-dir)%.o: %.cpp $(MAKEFILE_PATH) config.mk + $(Q)test -d $(dir $@) || echo $(MSG_MKDIR) +ifeq ($(os),Windows) + $(Q)test -d $(patsubst %/,%,$(dir $@)) || mkdir $(subst /,\,$(dir $@)) +else + $(Q)test -d $(dir $@) || mkdir -p $(dir $@) +endif + @echo $(MSG_COMPILING_CXX) + $(Q)$(CXX) $(cxx_flags) -c $< -o $@ + +# Preprocess and assemble: create object files from assembler source files. +$(build-dir)%.o: %.S $(MAKEFILE_PATH) config.mk + $(Q)test -d $(dir $@) || echo $(MSG_MKDIR) +ifeq ($(os),Windows) + $(Q)test -d $(patsubst %/,%,$(dir $@)) || mkdir $(subst /,\,$(dir $@)) +else + $(Q)test -d $(dir $@) || mkdir -p $(dir $@) +endif + @echo $(MSG_ASSEMBLING) + $(Q)$(CC) $(a_flags) -c $< -o $@ + +# Include all dependency files to add depedency to all header files in use. +include $(dep-files) + +ifeq ($(target_type),lib) +# Archive object files into an archive +$(target): $(MAKEFILE_PATH) config.mk $(obj-y) + @echo $(MSG_ARCHIVING) + $(Q)$(AR) $(ar_flags) $@ $(obj-y) + @echo $(MSG_SIZE) + $(Q)$(SIZE) -Bxt $@ +else +ifeq ($(target_type),elf) +# Link the object files into an ELF file. Also make sure the target is rebuilt +# if the common Makefile.sam.in or project config.mk is changed. +$(target): $(linker_script) $(MAKEFILE_PATH) config.mk $(obj-y) + @echo $(MSG_LINKING) + $(Q)$(LD) $(l_flags) $(obj-y) $(libflags-gnu-y) -o $@ + @echo $(MSG_SIZE) + $(Q)$(SIZE) -Ax $@ + $(Q)$(SIZE) -Bx $@ +endif +endif + +# Create extended function listing from target output file. +%.lss: $(target) + @echo $(MSG_EXTENDED_LISTING) + $(Q)$(OBJDUMP) -h -S $< > $@ + +# Create symbol table from target output file. +%.sym: $(target) + @echo $(MSG_SYMBOL_TABLE) + $(Q)$(NM) -n $< > $@ + +# Create Intel HEX image from ELF output file. +%.hex: $(target) + @echo $(MSG_IHEX_IMAGE) + $(Q)$(OBJCOPY) -O ihex $(flashflags-gnu-y) $< $@ + +# Create binary image from ELF output file. +%.bin: $(target) + @echo $(MSG_BINARY_IMAGE) + $(Q)$(OBJCOPY) -O binary $< $@ + +# Provide information about the detected host operating system. +.SECONDARY: info-os +info-os: + @echo $(MSG_INFO)$(os) build host detected + +# Build Doxygen generated documentation. +.PHONY: doc +doc: + @echo $(MSG_GENERATING_DOC) + $(Q)cd $(dir $(doccfg)) && $(DOCGEN) $(notdir $(doccfg)) + +# Clean Doxygen generated documentation. +.PHONY: cleandoc +cleandoc: + @$(if $(wildcard $(docdir)),echo $(MSG_CLEAN_DOC)) + $(Q)$(if $(wildcard $(docdir)),$(RM) --recursive $(docdir)) + +# Rebuild the Doxygen generated documentation. +.PHONY: rebuilddoc +rebuilddoc: cleandoc doc diff --git a/src/boards/mcu/samr34/ASF/sam0/utils/preprocessor/mrecursion.h b/src/boards/mcu/samr34/ASF/sam0/utils/preprocessor/mrecursion.h new file mode 100644 index 000000000..dc628e651 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/utils/preprocessor/mrecursion.h @@ -0,0 +1,588 @@ +/** + * \file + * + * \brief Preprocessor macro recursion utils. + * + * Copyright (c) 2013-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#ifndef _MRECURSION_H_ +#define _MRECURSION_H_ + +/** + * \defgroup group_sam0_utils_mrecursion Preprocessor - Macro Recursion + * + * \ingroup group_sam0_utils + * + * @{ + */ + +#include "preprocessor.h" + +#define DEC_256 255 +#define DEC_255 254 +#define DEC_254 253 +#define DEC_253 252 +#define DEC_252 251 +#define DEC_251 250 +#define DEC_250 249 +#define DEC_249 248 +#define DEC_248 247 +#define DEC_247 246 +#define DEC_246 245 +#define DEC_245 244 +#define DEC_244 243 +#define DEC_243 242 +#define DEC_242 241 +#define DEC_241 240 +#define DEC_240 239 +#define DEC_239 238 +#define DEC_238 237 +#define DEC_237 236 +#define DEC_236 235 +#define DEC_235 234 +#define DEC_234 233 +#define DEC_233 232 +#define DEC_232 231 +#define DEC_231 230 +#define DEC_230 229 +#define DEC_229 228 +#define DEC_228 227 +#define DEC_227 226 +#define DEC_226 225 +#define DEC_225 224 +#define DEC_224 223 +#define DEC_223 222 +#define DEC_222 221 +#define DEC_221 220 +#define DEC_220 219 +#define DEC_219 218 +#define DEC_218 217 +#define DEC_217 216 +#define DEC_216 215 +#define DEC_215 214 +#define DEC_214 213 +#define DEC_213 212 +#define DEC_212 211 +#define DEC_211 210 +#define DEC_210 209 +#define DEC_209 208 +#define DEC_208 207 +#define DEC_207 206 +#define DEC_206 205 +#define DEC_205 204 +#define DEC_204 203 +#define DEC_203 202 +#define DEC_202 201 +#define DEC_201 200 +#define DEC_200 199 +#define DEC_199 198 +#define DEC_198 197 +#define DEC_197 196 +#define DEC_196 195 +#define DEC_195 194 +#define DEC_194 193 +#define DEC_193 192 +#define DEC_192 191 +#define DEC_191 190 +#define DEC_190 189 +#define DEC_189 188 +#define DEC_188 187 +#define DEC_187 186 +#define DEC_186 185 +#define DEC_185 184 +#define DEC_184 183 +#define DEC_183 182 +#define DEC_182 181 +#define DEC_181 180 +#define DEC_180 179 +#define DEC_179 178 +#define DEC_178 177 +#define DEC_177 176 +#define DEC_176 175 +#define DEC_175 174 +#define DEC_174 173 +#define DEC_173 172 +#define DEC_172 171 +#define DEC_171 170 +#define DEC_170 169 +#define DEC_169 168 +#define DEC_168 167 +#define DEC_167 166 +#define DEC_166 165 +#define DEC_165 164 +#define DEC_164 163 +#define DEC_163 162 +#define DEC_162 161 +#define DEC_161 160 +#define DEC_160 159 +#define DEC_159 158 +#define DEC_158 157 +#define DEC_157 156 +#define DEC_156 155 +#define DEC_155 154 +#define DEC_154 153 +#define DEC_153 152 +#define DEC_152 151 +#define DEC_151 150 +#define DEC_150 149 +#define DEC_149 148 +#define DEC_148 147 +#define DEC_147 146 +#define DEC_146 145 +#define DEC_145 144 +#define DEC_144 143 +#define DEC_143 142 +#define DEC_142 141 +#define DEC_141 140 +#define DEC_140 139 +#define DEC_139 138 +#define DEC_138 137 +#define DEC_137 136 +#define DEC_136 135 +#define DEC_135 134 +#define DEC_134 133 +#define DEC_133 132 +#define DEC_132 131 +#define DEC_131 130 +#define DEC_130 129 +#define DEC_129 128 +#define DEC_128 127 +#define DEC_127 126 +#define DEC_126 125 +#define DEC_125 124 +#define DEC_124 123 +#define DEC_123 122 +#define DEC_122 121 +#define DEC_121 120 +#define DEC_120 119 +#define DEC_119 118 +#define DEC_118 117 +#define DEC_117 116 +#define DEC_116 115 +#define DEC_115 114 +#define DEC_114 113 +#define DEC_113 112 +#define DEC_112 111 +#define DEC_111 110 +#define DEC_110 109 +#define DEC_109 108 +#define DEC_108 107 +#define DEC_107 106 +#define DEC_106 105 +#define DEC_105 104 +#define DEC_104 103 +#define DEC_103 102 +#define DEC_102 101 +#define DEC_101 100 +#define DEC_100 99 +#define DEC_99 98 +#define DEC_98 97 +#define DEC_97 96 +#define DEC_96 95 +#define DEC_95 94 +#define DEC_94 93 +#define DEC_93 92 +#define DEC_92 91 +#define DEC_91 90 +#define DEC_90 89 +#define DEC_89 88 +#define DEC_88 87 +#define DEC_87 86 +#define DEC_86 85 +#define DEC_85 84 +#define DEC_84 83 +#define DEC_83 82 +#define DEC_82 81 +#define DEC_81 80 +#define DEC_80 79 +#define DEC_79 78 +#define DEC_78 77 +#define DEC_77 76 +#define DEC_76 75 +#define DEC_75 74 +#define DEC_74 73 +#define DEC_73 72 +#define DEC_72 71 +#define DEC_71 70 +#define DEC_70 69 +#define DEC_69 68 +#define DEC_68 67 +#define DEC_67 66 +#define DEC_66 65 +#define DEC_65 64 +#define DEC_64 63 +#define DEC_63 62 +#define DEC_62 61 +#define DEC_61 60 +#define DEC_60 59 +#define DEC_59 58 +#define DEC_58 57 +#define DEC_57 56 +#define DEC_56 55 +#define DEC_55 54 +#define DEC_54 53 +#define DEC_53 52 +#define DEC_52 51 +#define DEC_51 50 +#define DEC_50 49 +#define DEC_49 48 +#define DEC_48 47 +#define DEC_47 46 +#define DEC_46 45 +#define DEC_45 44 +#define DEC_44 43 +#define DEC_43 42 +#define DEC_42 41 +#define DEC_41 40 +#define DEC_40 39 +#define DEC_39 38 +#define DEC_38 37 +#define DEC_37 36 +#define DEC_36 35 +#define DEC_35 34 +#define DEC_34 33 +#define DEC_33 32 +#define DEC_32 31 +#define DEC_31 30 +#define DEC_30 29 +#define DEC_29 28 +#define DEC_28 27 +#define DEC_27 26 +#define DEC_26 25 +#define DEC_25 24 +#define DEC_24 23 +#define DEC_23 22 +#define DEC_22 21 +#define DEC_21 20 +#define DEC_20 19 +#define DEC_19 18 +#define DEC_18 17 +#define DEC_17 16 +#define DEC_16 15 +#define DEC_15 14 +#define DEC_14 13 +#define DEC_13 12 +#define DEC_12 11 +#define DEC_11 10 +#define DEC_10 9 +#define DEC_9 8 +#define DEC_8 7 +#define DEC_7 6 +#define DEC_6 5 +#define DEC_5 4 +#define DEC_4 3 +#define DEC_3 2 +#define DEC_2 1 +#define DEC_1 0 +#define DEC_(n) DEC_##n + + +/** Maximal number of repetitions supported by MRECURSION. */ +#define MRECURSION_LIMIT 256 + +/** \brief Macro recursion. + * + * This macro represents a horizontal repetition construct. + * + * \param[in] count The number of repetitious calls to macro. Valid values + * range from 0 to MRECURSION_LIMIT. + * \param[in] macro A binary operation of the form macro(data, n). This macro + * is expanded by MRECURSION with the current repetition number + * and the auxiliary data argument. + * \param[in] data A recursive threshold, building on this to decline by times + * defined with param count. + * + * \return macro(data-count+1,0) macro(data-count+2,1)...macro(data,count-1) + */ +#define MRECURSION(count, macro, data) TPASTE2(MRECURSION, count) (macro, data) + +#define MRECURSION0( macro, data) +#define MRECURSION1( macro, data) MRECURSION0( macro, DEC_(data)) macro(data, 0) +#define MRECURSION2( macro, data) MRECURSION1( macro, DEC_(data)) macro(data, 1) +#define MRECURSION3( macro, data) MRECURSION2( macro, DEC_(data)) macro(data, 2) +#define MRECURSION4( macro, data) MRECURSION3( macro, DEC_(data)) macro(data, 3) +#define MRECURSION5( macro, data) MRECURSION4( macro, DEC_(data)) macro(data, 4) +#define MRECURSION6( macro, data) MRECURSION5( macro, DEC_(data)) macro(data, 5) +#define MRECURSION7( macro, data) MRECURSION6( macro, DEC_(data)) macro(data, 6) +#define MRECURSION8( macro, data) MRECURSION7( macro, DEC_(data)) macro(data, 7) +#define MRECURSION9( macro, data) MRECURSION8( macro, DEC_(data)) macro(data, 8) +#define MRECURSION10( macro, data) MRECURSION9( macro, DEC_(data)) macro(data, 9) +#define MRECURSION11( macro, data) MRECURSION10( macro, DEC_(data)) macro(data, 10) +#define MRECURSION12( macro, data) MRECURSION11( macro, DEC_(data)) macro(data, 11) +#define MRECURSION13( macro, data) MRECURSION12( macro, DEC_(data)) macro(data, 12) +#define MRECURSION14( macro, data) MRECURSION13( macro, DEC_(data)) macro(data, 13) +#define MRECURSION15( macro, data) MRECURSION14( macro, DEC_(data)) macro(data, 14) +#define MRECURSION16( macro, data) MRECURSION15( macro, DEC_(data)) macro(data, 15) +#define MRECURSION17( macro, data) MRECURSION16( macro, DEC_(data)) macro(data, 16) +#define MRECURSION18( macro, data) MRECURSION17( macro, DEC_(data)) macro(data, 17) +#define MRECURSION19( macro, data) MRECURSION18( macro, DEC_(data)) macro(data, 18) +#define MRECURSION20( macro, data) MRECURSION19( macro, DEC_(data)) macro(data, 19) +#define MRECURSION21( macro, data) MRECURSION20( macro, DEC_(data)) macro(data, 20) +#define MRECURSION22( macro, data) MRECURSION21( macro, DEC_(data)) macro(data, 21) +#define MRECURSION23( macro, data) MRECURSION22( macro, DEC_(data)) macro(data, 22) +#define MRECURSION24( macro, data) MRECURSION23( macro, DEC_(data)) macro(data, 23) +#define MRECURSION25( macro, data) MRECURSION24( macro, DEC_(data)) macro(data, 24) +#define MRECURSION26( macro, data) MRECURSION25( macro, DEC_(data)) macro(data, 25) +#define MRECURSION27( macro, data) MRECURSION26( macro, DEC_(data)) macro(data, 26) +#define MRECURSION28( macro, data) MRECURSION27( macro, DEC_(data)) macro(data, 27) +#define MRECURSION29( macro, data) MRECURSION28( macro, DEC_(data)) macro(data, 28) +#define MRECURSION30( macro, data) MRECURSION29( macro, DEC_(data)) macro(data, 29) +#define MRECURSION31( macro, data) MRECURSION30( macro, DEC_(data)) macro(data, 30) +#define MRECURSION32( macro, data) MRECURSION31( macro, DEC_(data)) macro(data, 31) +#define MRECURSION33( macro, data) MRECURSION32( macro, DEC_(data)) macro(data, 32) +#define MRECURSION34( macro, data) MRECURSION33( macro, DEC_(data)) macro(data, 33) +#define MRECURSION35( macro, data) MRECURSION34( macro, DEC_(data)) macro(data, 34) +#define MRECURSION36( macro, data) MRECURSION35( macro, DEC_(data)) macro(data, 35) +#define MRECURSION37( macro, data) MRECURSION36( macro, DEC_(data)) macro(data, 36) +#define MRECURSION38( macro, data) MRECURSION37( macro, DEC_(data)) macro(data, 37) +#define MRECURSION39( macro, data) MRECURSION38( macro, DEC_(data)) macro(data, 38) +#define MRECURSION40( macro, data) MRECURSION39( macro, DEC_(data)) macro(data, 39) +#define MRECURSION41( macro, data) MRECURSION40( macro, DEC_(data)) macro(data, 40) +#define MRECURSION42( macro, data) MRECURSION41( macro, DEC_(data)) macro(data, 41) +#define MRECURSION43( macro, data) MRECURSION42( macro, DEC_(data)) macro(data, 42) +#define MRECURSION44( macro, data) MRECURSION43( macro, DEC_(data)) macro(data, 43) +#define MRECURSION45( macro, data) MRECURSION44( macro, DEC_(data)) macro(data, 44) +#define MRECURSION46( macro, data) MRECURSION45( macro, DEC_(data)) macro(data, 45) +#define MRECURSION47( macro, data) MRECURSION46( macro, DEC_(data)) macro(data, 46) +#define MRECURSION48( macro, data) MRECURSION47( macro, DEC_(data)) macro(data, 47) +#define MRECURSION49( macro, data) MRECURSION48( macro, DEC_(data)) macro(data, 48) +#define MRECURSION50( macro, data) MRECURSION49( macro, DEC_(data)) macro(data, 49) +#define MRECURSION51( macro, data) MRECURSION50( macro, DEC_(data)) macro(data, 50) +#define MRECURSION52( macro, data) MRECURSION51( macro, DEC_(data)) macro(data, 51) +#define MRECURSION53( macro, data) MRECURSION52( macro, DEC_(data)) macro(data, 52) +#define MRECURSION54( macro, data) MRECURSION53( macro, DEC_(data)) macro(data, 53) +#define MRECURSION55( macro, data) MRECURSION54( macro, DEC_(data)) macro(data, 54) +#define MRECURSION56( macro, data) MRECURSION55( macro, DEC_(data)) macro(data, 55) +#define MRECURSION57( macro, data) MRECURSION56( macro, DEC_(data)) macro(data, 56) +#define MRECURSION58( macro, data) MRECURSION57( macro, DEC_(data)) macro(data, 57) +#define MRECURSION59( macro, data) MRECURSION58( macro, DEC_(data)) macro(data, 58) +#define MRECURSION60( macro, data) MRECURSION59( macro, DEC_(data)) macro(data, 59) +#define MRECURSION61( macro, data) MRECURSION60( macro, DEC_(data)) macro(data, 60) +#define MRECURSION62( macro, data) MRECURSION61( macro, DEC_(data)) macro(data, 61) +#define MRECURSION63( macro, data) MRECURSION62( macro, DEC_(data)) macro(data, 62) +#define MRECURSION64( macro, data) MRECURSION63( macro, DEC_(data)) macro(data, 63) +#define MRECURSION65( macro, data) MRECURSION64( macro, DEC_(data)) macro(data, 64) +#define MRECURSION66( macro, data) MRECURSION65( macro, DEC_(data)) macro(data, 65) +#define MRECURSION67( macro, data) MRECURSION66( macro, DEC_(data)) macro(data, 66) +#define MRECURSION68( macro, data) MRECURSION67( macro, DEC_(data)) macro(data, 67) +#define MRECURSION69( macro, data) MRECURSION68( macro, DEC_(data)) macro(data, 68) +#define MRECURSION70( macro, data) MRECURSION69( macro, DEC_(data)) macro(data, 69) +#define MRECURSION71( macro, data) MRECURSION70( macro, DEC_(data)) macro(data, 70) +#define MRECURSION72( macro, data) MRECURSION71( macro, DEC_(data)) macro(data, 71) +#define MRECURSION73( macro, data) MRECURSION72( macro, DEC_(data)) macro(data, 72) +#define MRECURSION74( macro, data) MRECURSION73( macro, DEC_(data)) macro(data, 73) +#define MRECURSION75( macro, data) MRECURSION74( macro, DEC_(data)) macro(data, 74) +#define MRECURSION76( macro, data) MRECURSION75( macro, DEC_(data)) macro(data, 75) +#define MRECURSION77( macro, data) MRECURSION76( macro, DEC_(data)) macro(data, 76) +#define MRECURSION78( macro, data) MRECURSION77( macro, DEC_(data)) macro(data, 77) +#define MRECURSION79( macro, data) MRECURSION78( macro, DEC_(data)) macro(data, 78) +#define MRECURSION80( macro, data) MRECURSION79( macro, DEC_(data)) macro(data, 79) +#define MRECURSION81( macro, data) MRECURSION80( macro, DEC_(data)) macro(data, 80) +#define MRECURSION82( macro, data) MRECURSION81( macro, DEC_(data)) macro(data, 81) +#define MRECURSION83( macro, data) MRECURSION82( macro, DEC_(data)) macro(data, 82) +#define MRECURSION84( macro, data) MRECURSION83( macro, DEC_(data)) macro(data, 83) +#define MRECURSION85( macro, data) MRECURSION84( macro, DEC_(data)) macro(data, 84) +#define MRECURSION86( macro, data) MRECURSION85( macro, DEC_(data)) macro(data, 85) +#define MRECURSION87( macro, data) MRECURSION86( macro, DEC_(data)) macro(data, 86) +#define MRECURSION88( macro, data) MRECURSION87( macro, DEC_(data)) macro(data, 87) +#define MRECURSION89( macro, data) MRECURSION88( macro, DEC_(data)) macro(data, 88) +#define MRECURSION90( macro, data) MRECURSION89( macro, DEC_(data)) macro(data, 89) +#define MRECURSION91( macro, data) MRECURSION90( macro, DEC_(data)) macro(data, 90) +#define MRECURSION92( macro, data) MRECURSION91( macro, DEC_(data)) macro(data, 91) +#define MRECURSION93( macro, data) MRECURSION92( macro, DEC_(data)) macro(data, 92) +#define MRECURSION94( macro, data) MRECURSION93( macro, DEC_(data)) macro(data, 93) +#define MRECURSION95( macro, data) MRECURSION94( macro, DEC_(data)) macro(data, 94) +#define MRECURSION96( macro, data) MRECURSION95( macro, DEC_(data)) macro(data, 95) +#define MRECURSION97( macro, data) MRECURSION96( macro, DEC_(data)) macro(data, 96) +#define MRECURSION98( macro, data) MRECURSION97( macro, DEC_(data)) macro(data, 97) +#define MRECURSION99( macro, data) MRECURSION98( macro, DEC_(data)) macro(data, 98) +#define MRECURSION100(macro, data) MRECURSION99( macro, DEC_(data)) macro(data, 99) +#define MRECURSION101(macro, data) MRECURSION100( macro, DEC_(data)) macro(data, 100) +#define MRECURSION102(macro, data) MRECURSION101( macro, DEC_(data)) macro(data, 101) +#define MRECURSION103(macro, data) MRECURSION102( macro, DEC_(data)) macro(data, 102) +#define MRECURSION104(macro, data) MRECURSION103( macro, DEC_(data)) macro(data, 103) +#define MRECURSION105(macro, data) MRECURSION104( macro, DEC_(data)) macro(data, 104) +#define MRECURSION106(macro, data) MRECURSION105( macro, DEC_(data)) macro(data, 105) +#define MRECURSION107(macro, data) MRECURSION106( macro, DEC_(data)) macro(data, 106) +#define MRECURSION108(macro, data) MRECURSION107( macro, DEC_(data)) macro(data, 107) +#define MRECURSION109(macro, data) MRECURSION108( macro, DEC_(data)) macro(data, 108) +#define MRECURSION110(macro, data) MRECURSION109( macro, DEC_(data)) macro(data, 109) +#define MRECURSION111(macro, data) MRECURSION110( macro, DEC_(data)) macro(data, 110) +#define MRECURSION112(macro, data) MRECURSION111( macro, DEC_(data)) macro(data, 111) +#define MRECURSION113(macro, data) MRECURSION112( macro, DEC_(data)) macro(data, 112) +#define MRECURSION114(macro, data) MRECURSION113( macro, DEC_(data)) macro(data, 113) +#define MRECURSION115(macro, data) MRECURSION114( macro, DEC_(data)) macro(data, 114) +#define MRECURSION116(macro, data) MRECURSION115( macro, DEC_(data)) macro(data, 115) +#define MRECURSION117(macro, data) MRECURSION116( macro, DEC_(data)) macro(data, 116) +#define MRECURSION118(macro, data) MRECURSION117( macro, DEC_(data)) macro(data, 117) +#define MRECURSION119(macro, data) MRECURSION118( macro, DEC_(data)) macro(data, 118) +#define MRECURSION120(macro, data) MRECURSION119( macro, DEC_(data)) macro(data, 119) +#define MRECURSION121(macro, data) MRECURSION120( macro, DEC_(data)) macro(data, 120) +#define MRECURSION122(macro, data) MRECURSION121( macro, DEC_(data)) macro(data, 121) +#define MRECURSION123(macro, data) MRECURSION122( macro, DEC_(data)) macro(data, 122) +#define MRECURSION124(macro, data) MRECURSION123( macro, DEC_(data)) macro(data, 123) +#define MRECURSION125(macro, data) MRECURSION124( macro, DEC_(data)) macro(data, 124) +#define MRECURSION126(macro, data) MRECURSION125( macro, DEC_(data)) macro(data, 125) +#define MRECURSION127(macro, data) MRECURSION126( macro, DEC_(data)) macro(data, 126) +#define MRECURSION128(macro, data) MRECURSION127( macro, DEC_(data)) macro(data, 127) +#define MRECURSION129(macro, data) MRECURSION128( macro, DEC_(data)) macro(data, 128) +#define MRECURSION130(macro, data) MRECURSION129( macro, DEC_(data)) macro(data, 129) +#define MRECURSION131(macro, data) MRECURSION130( macro, DEC_(data)) macro(data, 130) +#define MRECURSION132(macro, data) MRECURSION131( macro, DEC_(data)) macro(data, 131) +#define MRECURSION133(macro, data) MRECURSION132( macro, DEC_(data)) macro(data, 132) +#define MRECURSION134(macro, data) MRECURSION133( macro, DEC_(data)) macro(data, 133) +#define MRECURSION135(macro, data) MRECURSION134( macro, DEC_(data)) macro(data, 134) +#define MRECURSION136(macro, data) MRECURSION135( macro, DEC_(data)) macro(data, 135) +#define MRECURSION137(macro, data) MRECURSION136( macro, DEC_(data)) macro(data, 136) +#define MRECURSION138(macro, data) MRECURSION137( macro, DEC_(data)) macro(data, 137) +#define MRECURSION139(macro, data) MRECURSION138( macro, DEC_(data)) macro(data, 138) +#define MRECURSION140(macro, data) MRECURSION139( macro, DEC_(data)) macro(data, 139) +#define MRECURSION141(macro, data) MRECURSION140( macro, DEC_(data)) macro(data, 140) +#define MRECURSION142(macro, data) MRECURSION141( macro, DEC_(data)) macro(data, 141) +#define MRECURSION143(macro, data) MRECURSION142( macro, DEC_(data)) macro(data, 142) +#define MRECURSION144(macro, data) MRECURSION143( macro, DEC_(data)) macro(data, 143) +#define MRECURSION145(macro, data) MRECURSION144( macro, DEC_(data)) macro(data, 144) +#define MRECURSION146(macro, data) MRECURSION145( macro, DEC_(data)) macro(data, 145) +#define MRECURSION147(macro, data) MRECURSION146( macro, DEC_(data)) macro(data, 146) +#define MRECURSION148(macro, data) MRECURSION147( macro, DEC_(data)) macro(data, 147) +#define MRECURSION149(macro, data) MRECURSION148( macro, DEC_(data)) macro(data, 148) +#define MRECURSION150(macro, data) MRECURSION149( macro, DEC_(data)) macro(data, 149) +#define MRECURSION151(macro, data) MRECURSION150( macro, DEC_(data)) macro(data, 150) +#define MRECURSION152(macro, data) MRECURSION151( macro, DEC_(data)) macro(data, 151) +#define MRECURSION153(macro, data) MRECURSION152( macro, DEC_(data)) macro(data, 152) +#define MRECURSION154(macro, data) MRECURSION153( macro, DEC_(data)) macro(data, 153) +#define MRECURSION155(macro, data) MRECURSION154( macro, DEC_(data)) macro(data, 154) +#define MRECURSION156(macro, data) MRECURSION155( macro, DEC_(data)) macro(data, 155) +#define MRECURSION157(macro, data) MRECURSION156( macro, DEC_(data)) macro(data, 156) +#define MRECURSION158(macro, data) MRECURSION157( macro, DEC_(data)) macro(data, 157) +#define MRECURSION159(macro, data) MRECURSION158( macro, DEC_(data)) macro(data, 158) +#define MRECURSION160(macro, data) MRECURSION159( macro, DEC_(data)) macro(data, 159) +#define MRECURSION161(macro, data) MRECURSION160( macro, DEC_(data)) macro(data, 160) +#define MRECURSION162(macro, data) MRECURSION161( macro, DEC_(data)) macro(data, 161) +#define MRECURSION163(macro, data) MRECURSION162( macro, DEC_(data)) macro(data, 162) +#define MRECURSION164(macro, data) MRECURSION163( macro, DEC_(data)) macro(data, 163) +#define MRECURSION165(macro, data) MRECURSION164( macro, DEC_(data)) macro(data, 164) +#define MRECURSION166(macro, data) MRECURSION165( macro, DEC_(data)) macro(data, 165) +#define MRECURSION167(macro, data) MRECURSION166( macro, DEC_(data)) macro(data, 166) +#define MRECURSION168(macro, data) MRECURSION167( macro, DEC_(data)) macro(data, 167) +#define MRECURSION169(macro, data) MRECURSION168( macro, DEC_(data)) macro(data, 168) +#define MRECURSION170(macro, data) MRECURSION169( macro, DEC_(data)) macro(data, 169) +#define MRECURSION171(macro, data) MRECURSION170( macro, DEC_(data)) macro(data, 170) +#define MRECURSION172(macro, data) MRECURSION171( macro, DEC_(data)) macro(data, 171) +#define MRECURSION173(macro, data) MRECURSION172( macro, DEC_(data)) macro(data, 172) +#define MRECURSION174(macro, data) MRECURSION173( macro, DEC_(data)) macro(data, 173) +#define MRECURSION175(macro, data) MRECURSION174( macro, DEC_(data)) macro(data, 174) +#define MRECURSION176(macro, data) MRECURSION175( macro, DEC_(data)) macro(data, 175) +#define MRECURSION177(macro, data) MRECURSION176( macro, DEC_(data)) macro(data, 176) +#define MRECURSION178(macro, data) MRECURSION177( macro, DEC_(data)) macro(data, 177) +#define MRECURSION179(macro, data) MRECURSION178( macro, DEC_(data)) macro(data, 178) +#define MRECURSION180(macro, data) MRECURSION179( macro, DEC_(data)) macro(data, 179) +#define MRECURSION181(macro, data) MRECURSION180( macro, DEC_(data)) macro(data, 180) +#define MRECURSION182(macro, data) MRECURSION181( macro, DEC_(data)) macro(data, 181) +#define MRECURSION183(macro, data) MRECURSION182( macro, DEC_(data)) macro(data, 182) +#define MRECURSION184(macro, data) MRECURSION183( macro, DEC_(data)) macro(data, 183) +#define MRECURSION185(macro, data) MRECURSION184( macro, DEC_(data)) macro(data, 184) +#define MRECURSION186(macro, data) MRECURSION185( macro, DEC_(data)) macro(data, 185) +#define MRECURSION187(macro, data) MRECURSION186( macro, DEC_(data)) macro(data, 186) +#define MRECURSION188(macro, data) MRECURSION187( macro, DEC_(data)) macro(data, 187) +#define MRECURSION189(macro, data) MRECURSION188( macro, DEC_(data)) macro(data, 188) +#define MRECURSION190(macro, data) MRECURSION189( macro, DEC_(data)) macro(data, 189) +#define MRECURSION191(macro, data) MRECURSION190( macro, DEC_(data)) macro(data, 190) +#define MRECURSION192(macro, data) MRECURSION191( macro, DEC_(data)) macro(data, 191) +#define MRECURSION193(macro, data) MRECURSION192( macro, DEC_(data)) macro(data, 192) +#define MRECURSION194(macro, data) MRECURSION193( macro, DEC_(data)) macro(data, 193) +#define MRECURSION195(macro, data) MRECURSION194( macro, DEC_(data)) macro(data, 194) +#define MRECURSION196(macro, data) MRECURSION195( macro, DEC_(data)) macro(data, 195) +#define MRECURSION197(macro, data) MRECURSION196( macro, DEC_(data)) macro(data, 196) +#define MRECURSION198(macro, data) MRECURSION197( macro, DEC_(data)) macro(data, 197) +#define MRECURSION199(macro, data) MRECURSION198( macro, DEC_(data)) macro(data, 198) +#define MRECURSION200(macro, data) MRECURSION199( macro, DEC_(data)) macro(data, 199) +#define MRECURSION201(macro, data) MRECURSION200( macro, DEC_(data)) macro(data, 200) +#define MRECURSION202(macro, data) MRECURSION201( macro, DEC_(data)) macro(data, 201) +#define MRECURSION203(macro, data) MRECURSION202( macro, DEC_(data)) macro(data, 202) +#define MRECURSION204(macro, data) MRECURSION203( macro, DEC_(data)) macro(data, 203) +#define MRECURSION205(macro, data) MRECURSION204( macro, DEC_(data)) macro(data, 204) +#define MRECURSION206(macro, data) MRECURSION205( macro, DEC_(data)) macro(data, 205) +#define MRECURSION207(macro, data) MRECURSION206( macro, DEC_(data)) macro(data, 206) +#define MRECURSION208(macro, data) MRECURSION207( macro, DEC_(data)) macro(data, 207) +#define MRECURSION209(macro, data) MRECURSION208( macro, DEC_(data)) macro(data, 208) +#define MRECURSION210(macro, data) MRECURSION209( macro, DEC_(data)) macro(data, 209) +#define MRECURSION211(macro, data) MRECURSION210( macro, DEC_(data)) macro(data, 210) +#define MRECURSION212(macro, data) MRECURSION211( macro, DEC_(data)) macro(data, 211) +#define MRECURSION213(macro, data) MRECURSION212( macro, DEC_(data)) macro(data, 212) +#define MRECURSION214(macro, data) MRECURSION213( macro, DEC_(data)) macro(data, 213) +#define MRECURSION215(macro, data) MRECURSION214( macro, DEC_(data)) macro(data, 214) +#define MRECURSION216(macro, data) MRECURSION215( macro, DEC_(data)) macro(data, 215) +#define MRECURSION217(macro, data) MRECURSION216( macro, DEC_(data)) macro(data, 216) +#define MRECURSION218(macro, data) MRECURSION217( macro, DEC_(data)) macro(data, 217) +#define MRECURSION219(macro, data) MRECURSION218( macro, DEC_(data)) macro(data, 218) +#define MRECURSION220(macro, data) MRECURSION219( macro, DEC_(data)) macro(data, 219) +#define MRECURSION221(macro, data) MRECURSION220( macro, DEC_(data)) macro(data, 220) +#define MRECURSION222(macro, data) MRECURSION221( macro, DEC_(data)) macro(data, 221) +#define MRECURSION223(macro, data) MRECURSION222( macro, DEC_(data)) macro(data, 222) +#define MRECURSION224(macro, data) MRECURSION223( macro, DEC_(data)) macro(data, 223) +#define MRECURSION225(macro, data) MRECURSION224( macro, DEC_(data)) macro(data, 224) +#define MRECURSION226(macro, data) MRECURSION225( macro, DEC_(data)) macro(data, 225) +#define MRECURSION227(macro, data) MRECURSION226( macro, DEC_(data)) macro(data, 226) +#define MRECURSION228(macro, data) MRECURSION227( macro, DEC_(data)) macro(data, 227) +#define MRECURSION229(macro, data) MRECURSION228( macro, DEC_(data)) macro(data, 228) +#define MRECURSION230(macro, data) MRECURSION229( macro, DEC_(data)) macro(data, 229) +#define MRECURSION231(macro, data) MRECURSION230( macro, DEC_(data)) macro(data, 230) +#define MRECURSION232(macro, data) MRECURSION231( macro, DEC_(data)) macro(data, 231) +#define MRECURSION233(macro, data) MRECURSION232( macro, DEC_(data)) macro(data, 232) +#define MRECURSION234(macro, data) MRECURSION233( macro, DEC_(data)) macro(data, 233) +#define MRECURSION235(macro, data) MRECURSION234( macro, DEC_(data)) macro(data, 234) +#define MRECURSION236(macro, data) MRECURSION235( macro, DEC_(data)) macro(data, 235) +#define MRECURSION237(macro, data) MRECURSION236( macro, DEC_(data)) macro(data, 236) +#define MRECURSION238(macro, data) MRECURSION237( macro, DEC_(data)) macro(data, 237) +#define MRECURSION239(macro, data) MRECURSION238( macro, DEC_(data)) macro(data, 238) +#define MRECURSION240(macro, data) MRECURSION239( macro, DEC_(data)) macro(data, 239) +#define MRECURSION241(macro, data) MRECURSION240( macro, DEC_(data)) macro(data, 240) +#define MRECURSION242(macro, data) MRECURSION241( macro, DEC_(data)) macro(data, 241) +#define MRECURSION243(macro, data) MRECURSION242( macro, DEC_(data)) macro(data, 242) +#define MRECURSION244(macro, data) MRECURSION243( macro, DEC_(data)) macro(data, 243) +#define MRECURSION245(macro, data) MRECURSION244( macro, DEC_(data)) macro(data, 244) +#define MRECURSION246(macro, data) MRECURSION245( macro, DEC_(data)) macro(data, 245) +#define MRECURSION247(macro, data) MRECURSION246( macro, DEC_(data)) macro(data, 246) +#define MRECURSION248(macro, data) MRECURSION247( macro, DEC_(data)) macro(data, 247) +#define MRECURSION249(macro, data) MRECURSION248( macro, DEC_(data)) macro(data, 248) +#define MRECURSION250(macro, data) MRECURSION249( macro, DEC_(data)) macro(data, 249) +#define MRECURSION251(macro, data) MRECURSION250( macro, DEC_(data)) macro(data, 250) +#define MRECURSION252(macro, data) MRECURSION251( macro, DEC_(data)) macro(data, 251) +#define MRECURSION253(macro, data) MRECURSION252( macro, DEC_(data)) macro(data, 252) +#define MRECURSION254(macro, data) MRECURSION253( macro, DEC_(data)) macro(data, 253) +#define MRECURSION255(macro, data) MRECURSION254( macro, DEC_(data)) macro(data, 254) +#define MRECURSION256(macro, data) MRECURSION255( macro, DEC_(data)) macro(data, 255) + +/** @} */ + +#endif /* _MRECURSION_H_ */ diff --git a/src/boards/mcu/samr34/ASF/sam0/utils/preprocessor/mrepeat.h b/src/boards/mcu/samr34/ASF/sam0/utils/preprocessor/mrepeat.h new file mode 100644 index 000000000..045c197d8 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/utils/preprocessor/mrepeat.h @@ -0,0 +1,328 @@ +/** + * \file + * + * \brief Preprocessor macro repeating utils. + * + * Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#ifndef _MREPEAT_H_ +#define _MREPEAT_H_ + +/** + * \defgroup group_sam0_utils_mrepeat Preprocessor - Macro Repeat + * + * \ingroup group_sam0_utils + * + * @{ + */ + +#include "preprocessor.h" + +/** Maximal number of repetitions supported by MREPEAT. */ +#define MREPEAT_LIMIT 256 + +/** \brief Macro repeat. + * + * This macro represents a horizontal repetition construct. + * + * \param[in] count The number of repetitious calls to macro. Valid values + * range from 0 to MREPEAT_LIMIT. + * \param[in] macro A binary operation of the form macro(n, data). This macro + * is expanded by MREPEAT with the current repetition number + * and the auxiliary data argument. + * \param[in] data Auxiliary data passed to macro. + * + * \return macro(0, data) macro(1, data) ... macro(count - 1, data) + */ +#define MREPEAT(count, macro, data) TPASTE2(MREPEAT, count) (macro, data) + +#define MREPEAT0( macro, data) +#define MREPEAT1( macro, data) MREPEAT0( macro, data) macro( 0, data) +#define MREPEAT2( macro, data) MREPEAT1( macro, data) macro( 1, data) +#define MREPEAT3( macro, data) MREPEAT2( macro, data) macro( 2, data) +#define MREPEAT4( macro, data) MREPEAT3( macro, data) macro( 3, data) +#define MREPEAT5( macro, data) MREPEAT4( macro, data) macro( 4, data) +#define MREPEAT6( macro, data) MREPEAT5( macro, data) macro( 5, data) +#define MREPEAT7( macro, data) MREPEAT6( macro, data) macro( 6, data) +#define MREPEAT8( macro, data) MREPEAT7( macro, data) macro( 7, data) +#define MREPEAT9( macro, data) MREPEAT8( macro, data) macro( 8, data) +#define MREPEAT10( macro, data) MREPEAT9( macro, data) macro( 9, data) +#define MREPEAT11( macro, data) MREPEAT10( macro, data) macro( 10, data) +#define MREPEAT12( macro, data) MREPEAT11( macro, data) macro( 11, data) +#define MREPEAT13( macro, data) MREPEAT12( macro, data) macro( 12, data) +#define MREPEAT14( macro, data) MREPEAT13( macro, data) macro( 13, data) +#define MREPEAT15( macro, data) MREPEAT14( macro, data) macro( 14, data) +#define MREPEAT16( macro, data) MREPEAT15( macro, data) macro( 15, data) +#define MREPEAT17( macro, data) MREPEAT16( macro, data) macro( 16, data) +#define MREPEAT18( macro, data) MREPEAT17( macro, data) macro( 17, data) +#define MREPEAT19( macro, data) MREPEAT18( macro, data) macro( 18, data) +#define MREPEAT20( macro, data) MREPEAT19( macro, data) macro( 19, data) +#define MREPEAT21( macro, data) MREPEAT20( macro, data) macro( 20, data) +#define MREPEAT22( macro, data) MREPEAT21( macro, data) macro( 21, data) +#define MREPEAT23( macro, data) MREPEAT22( macro, data) macro( 22, data) +#define MREPEAT24( macro, data) MREPEAT23( macro, data) macro( 23, data) +#define MREPEAT25( macro, data) MREPEAT24( macro, data) macro( 24, data) +#define MREPEAT26( macro, data) MREPEAT25( macro, data) macro( 25, data) +#define MREPEAT27( macro, data) MREPEAT26( macro, data) macro( 26, data) +#define MREPEAT28( macro, data) MREPEAT27( macro, data) macro( 27, data) +#define MREPEAT29( macro, data) MREPEAT28( macro, data) macro( 28, data) +#define MREPEAT30( macro, data) MREPEAT29( macro, data) macro( 29, data) +#define MREPEAT31( macro, data) MREPEAT30( macro, data) macro( 30, data) +#define MREPEAT32( macro, data) MREPEAT31( macro, data) macro( 31, data) +#define MREPEAT33( macro, data) MREPEAT32( macro, data) macro( 32, data) +#define MREPEAT34( macro, data) MREPEAT33( macro, data) macro( 33, data) +#define MREPEAT35( macro, data) MREPEAT34( macro, data) macro( 34, data) +#define MREPEAT36( macro, data) MREPEAT35( macro, data) macro( 35, data) +#define MREPEAT37( macro, data) MREPEAT36( macro, data) macro( 36, data) +#define MREPEAT38( macro, data) MREPEAT37( macro, data) macro( 37, data) +#define MREPEAT39( macro, data) MREPEAT38( macro, data) macro( 38, data) +#define MREPEAT40( macro, data) MREPEAT39( macro, data) macro( 39, data) +#define MREPEAT41( macro, data) MREPEAT40( macro, data) macro( 40, data) +#define MREPEAT42( macro, data) MREPEAT41( macro, data) macro( 41, data) +#define MREPEAT43( macro, data) MREPEAT42( macro, data) macro( 42, data) +#define MREPEAT44( macro, data) MREPEAT43( macro, data) macro( 43, data) +#define MREPEAT45( macro, data) MREPEAT44( macro, data) macro( 44, data) +#define MREPEAT46( macro, data) MREPEAT45( macro, data) macro( 45, data) +#define MREPEAT47( macro, data) MREPEAT46( macro, data) macro( 46, data) +#define MREPEAT48( macro, data) MREPEAT47( macro, data) macro( 47, data) +#define MREPEAT49( macro, data) MREPEAT48( macro, data) macro( 48, data) +#define MREPEAT50( macro, data) MREPEAT49( macro, data) macro( 49, data) +#define MREPEAT51( macro, data) MREPEAT50( macro, data) macro( 50, data) +#define MREPEAT52( macro, data) MREPEAT51( macro, data) macro( 51, data) +#define MREPEAT53( macro, data) MREPEAT52( macro, data) macro( 52, data) +#define MREPEAT54( macro, data) MREPEAT53( macro, data) macro( 53, data) +#define MREPEAT55( macro, data) MREPEAT54( macro, data) macro( 54, data) +#define MREPEAT56( macro, data) MREPEAT55( macro, data) macro( 55, data) +#define MREPEAT57( macro, data) MREPEAT56( macro, data) macro( 56, data) +#define MREPEAT58( macro, data) MREPEAT57( macro, data) macro( 57, data) +#define MREPEAT59( macro, data) MREPEAT58( macro, data) macro( 58, data) +#define MREPEAT60( macro, data) MREPEAT59( macro, data) macro( 59, data) +#define MREPEAT61( macro, data) MREPEAT60( macro, data) macro( 60, data) +#define MREPEAT62( macro, data) MREPEAT61( macro, data) macro( 61, data) +#define MREPEAT63( macro, data) MREPEAT62( macro, data) macro( 62, data) +#define MREPEAT64( macro, data) MREPEAT63( macro, data) macro( 63, data) +#define MREPEAT65( macro, data) MREPEAT64( macro, data) macro( 64, data) +#define MREPEAT66( macro, data) MREPEAT65( macro, data) macro( 65, data) +#define MREPEAT67( macro, data) MREPEAT66( macro, data) macro( 66, data) +#define MREPEAT68( macro, data) MREPEAT67( macro, data) macro( 67, data) +#define MREPEAT69( macro, data) MREPEAT68( macro, data) macro( 68, data) +#define MREPEAT70( macro, data) MREPEAT69( macro, data) macro( 69, data) +#define MREPEAT71( macro, data) MREPEAT70( macro, data) macro( 70, data) +#define MREPEAT72( macro, data) MREPEAT71( macro, data) macro( 71, data) +#define MREPEAT73( macro, data) MREPEAT72( macro, data) macro( 72, data) +#define MREPEAT74( macro, data) MREPEAT73( macro, data) macro( 73, data) +#define MREPEAT75( macro, data) MREPEAT74( macro, data) macro( 74, data) +#define MREPEAT76( macro, data) MREPEAT75( macro, data) macro( 75, data) +#define MREPEAT77( macro, data) MREPEAT76( macro, data) macro( 76, data) +#define MREPEAT78( macro, data) MREPEAT77( macro, data) macro( 77, data) +#define MREPEAT79( macro, data) MREPEAT78( macro, data) macro( 78, data) +#define MREPEAT80( macro, data) MREPEAT79( macro, data) macro( 79, data) +#define MREPEAT81( macro, data) MREPEAT80( macro, data) macro( 80, data) +#define MREPEAT82( macro, data) MREPEAT81( macro, data) macro( 81, data) +#define MREPEAT83( macro, data) MREPEAT82( macro, data) macro( 82, data) +#define MREPEAT84( macro, data) MREPEAT83( macro, data) macro( 83, data) +#define MREPEAT85( macro, data) MREPEAT84( macro, data) macro( 84, data) +#define MREPEAT86( macro, data) MREPEAT85( macro, data) macro( 85, data) +#define MREPEAT87( macro, data) MREPEAT86( macro, data) macro( 86, data) +#define MREPEAT88( macro, data) MREPEAT87( macro, data) macro( 87, data) +#define MREPEAT89( macro, data) MREPEAT88( macro, data) macro( 88, data) +#define MREPEAT90( macro, data) MREPEAT89( macro, data) macro( 89, data) +#define MREPEAT91( macro, data) MREPEAT90( macro, data) macro( 90, data) +#define MREPEAT92( macro, data) MREPEAT91( macro, data) macro( 91, data) +#define MREPEAT93( macro, data) MREPEAT92( macro, data) macro( 92, data) +#define MREPEAT94( macro, data) MREPEAT93( macro, data) macro( 93, data) +#define MREPEAT95( macro, data) MREPEAT94( macro, data) macro( 94, data) +#define MREPEAT96( macro, data) MREPEAT95( macro, data) macro( 95, data) +#define MREPEAT97( macro, data) MREPEAT96( macro, data) macro( 96, data) +#define MREPEAT98( macro, data) MREPEAT97( macro, data) macro( 97, data) +#define MREPEAT99( macro, data) MREPEAT98( macro, data) macro( 98, data) +#define MREPEAT100(macro, data) MREPEAT99( macro, data) macro( 99, data) +#define MREPEAT101(macro, data) MREPEAT100(macro, data) macro(100, data) +#define MREPEAT102(macro, data) MREPEAT101(macro, data) macro(101, data) +#define MREPEAT103(macro, data) MREPEAT102(macro, data) macro(102, data) +#define MREPEAT104(macro, data) MREPEAT103(macro, data) macro(103, data) +#define MREPEAT105(macro, data) MREPEAT104(macro, data) macro(104, data) +#define MREPEAT106(macro, data) MREPEAT105(macro, data) macro(105, data) +#define MREPEAT107(macro, data) MREPEAT106(macro, data) macro(106, data) +#define MREPEAT108(macro, data) MREPEAT107(macro, data) macro(107, data) +#define MREPEAT109(macro, data) MREPEAT108(macro, data) macro(108, data) +#define MREPEAT110(macro, data) MREPEAT109(macro, data) macro(109, data) +#define MREPEAT111(macro, data) MREPEAT110(macro, data) macro(110, data) +#define MREPEAT112(macro, data) MREPEAT111(macro, data) macro(111, data) +#define MREPEAT113(macro, data) MREPEAT112(macro, data) macro(112, data) +#define MREPEAT114(macro, data) MREPEAT113(macro, data) macro(113, data) +#define MREPEAT115(macro, data) MREPEAT114(macro, data) macro(114, data) +#define MREPEAT116(macro, data) MREPEAT115(macro, data) macro(115, data) +#define MREPEAT117(macro, data) MREPEAT116(macro, data) macro(116, data) +#define MREPEAT118(macro, data) MREPEAT117(macro, data) macro(117, data) +#define MREPEAT119(macro, data) MREPEAT118(macro, data) macro(118, data) +#define MREPEAT120(macro, data) MREPEAT119(macro, data) macro(119, data) +#define MREPEAT121(macro, data) MREPEAT120(macro, data) macro(120, data) +#define MREPEAT122(macro, data) MREPEAT121(macro, data) macro(121, data) +#define MREPEAT123(macro, data) MREPEAT122(macro, data) macro(122, data) +#define MREPEAT124(macro, data) MREPEAT123(macro, data) macro(123, data) +#define MREPEAT125(macro, data) MREPEAT124(macro, data) macro(124, data) +#define MREPEAT126(macro, data) MREPEAT125(macro, data) macro(125, data) +#define MREPEAT127(macro, data) MREPEAT126(macro, data) macro(126, data) +#define MREPEAT128(macro, data) MREPEAT127(macro, data) macro(127, data) +#define MREPEAT129(macro, data) MREPEAT128(macro, data) macro(128, data) +#define MREPEAT130(macro, data) MREPEAT129(macro, data) macro(129, data) +#define MREPEAT131(macro, data) MREPEAT130(macro, data) macro(130, data) +#define MREPEAT132(macro, data) MREPEAT131(macro, data) macro(131, data) +#define MREPEAT133(macro, data) MREPEAT132(macro, data) macro(132, data) +#define MREPEAT134(macro, data) MREPEAT133(macro, data) macro(133, data) +#define MREPEAT135(macro, data) MREPEAT134(macro, data) macro(134, data) +#define MREPEAT136(macro, data) MREPEAT135(macro, data) macro(135, data) +#define MREPEAT137(macro, data) MREPEAT136(macro, data) macro(136, data) +#define MREPEAT138(macro, data) MREPEAT137(macro, data) macro(137, data) +#define MREPEAT139(macro, data) MREPEAT138(macro, data) macro(138, data) +#define MREPEAT140(macro, data) MREPEAT139(macro, data) macro(139, data) +#define MREPEAT141(macro, data) MREPEAT140(macro, data) macro(140, data) +#define MREPEAT142(macro, data) MREPEAT141(macro, data) macro(141, data) +#define MREPEAT143(macro, data) MREPEAT142(macro, data) macro(142, data) +#define MREPEAT144(macro, data) MREPEAT143(macro, data) macro(143, data) +#define MREPEAT145(macro, data) MREPEAT144(macro, data) macro(144, data) +#define MREPEAT146(macro, data) MREPEAT145(macro, data) macro(145, data) +#define MREPEAT147(macro, data) MREPEAT146(macro, data) macro(146, data) +#define MREPEAT148(macro, data) MREPEAT147(macro, data) macro(147, data) +#define MREPEAT149(macro, data) MREPEAT148(macro, data) macro(148, data) +#define MREPEAT150(macro, data) MREPEAT149(macro, data) macro(149, data) +#define MREPEAT151(macro, data) MREPEAT150(macro, data) macro(150, data) +#define MREPEAT152(macro, data) MREPEAT151(macro, data) macro(151, data) +#define MREPEAT153(macro, data) MREPEAT152(macro, data) macro(152, data) +#define MREPEAT154(macro, data) MREPEAT153(macro, data) macro(153, data) +#define MREPEAT155(macro, data) MREPEAT154(macro, data) macro(154, data) +#define MREPEAT156(macro, data) MREPEAT155(macro, data) macro(155, data) +#define MREPEAT157(macro, data) MREPEAT156(macro, data) macro(156, data) +#define MREPEAT158(macro, data) MREPEAT157(macro, data) macro(157, data) +#define MREPEAT159(macro, data) MREPEAT158(macro, data) macro(158, data) +#define MREPEAT160(macro, data) MREPEAT159(macro, data) macro(159, data) +#define MREPEAT161(macro, data) MREPEAT160(macro, data) macro(160, data) +#define MREPEAT162(macro, data) MREPEAT161(macro, data) macro(161, data) +#define MREPEAT163(macro, data) MREPEAT162(macro, data) macro(162, data) +#define MREPEAT164(macro, data) MREPEAT163(macro, data) macro(163, data) +#define MREPEAT165(macro, data) MREPEAT164(macro, data) macro(164, data) +#define MREPEAT166(macro, data) MREPEAT165(macro, data) macro(165, data) +#define MREPEAT167(macro, data) MREPEAT166(macro, data) macro(166, data) +#define MREPEAT168(macro, data) MREPEAT167(macro, data) macro(167, data) +#define MREPEAT169(macro, data) MREPEAT168(macro, data) macro(168, data) +#define MREPEAT170(macro, data) MREPEAT169(macro, data) macro(169, data) +#define MREPEAT171(macro, data) MREPEAT170(macro, data) macro(170, data) +#define MREPEAT172(macro, data) MREPEAT171(macro, data) macro(171, data) +#define MREPEAT173(macro, data) MREPEAT172(macro, data) macro(172, data) +#define MREPEAT174(macro, data) MREPEAT173(macro, data) macro(173, data) +#define MREPEAT175(macro, data) MREPEAT174(macro, data) macro(174, data) +#define MREPEAT176(macro, data) MREPEAT175(macro, data) macro(175, data) +#define MREPEAT177(macro, data) MREPEAT176(macro, data) macro(176, data) +#define MREPEAT178(macro, data) MREPEAT177(macro, data) macro(177, data) +#define MREPEAT179(macro, data) MREPEAT178(macro, data) macro(178, data) +#define MREPEAT180(macro, data) MREPEAT179(macro, data) macro(179, data) +#define MREPEAT181(macro, data) MREPEAT180(macro, data) macro(180, data) +#define MREPEAT182(macro, data) MREPEAT181(macro, data) macro(181, data) +#define MREPEAT183(macro, data) MREPEAT182(macro, data) macro(182, data) +#define MREPEAT184(macro, data) MREPEAT183(macro, data) macro(183, data) +#define MREPEAT185(macro, data) MREPEAT184(macro, data) macro(184, data) +#define MREPEAT186(macro, data) MREPEAT185(macro, data) macro(185, data) +#define MREPEAT187(macro, data) MREPEAT186(macro, data) macro(186, data) +#define MREPEAT188(macro, data) MREPEAT187(macro, data) macro(187, data) +#define MREPEAT189(macro, data) MREPEAT188(macro, data) macro(188, data) +#define MREPEAT190(macro, data) MREPEAT189(macro, data) macro(189, data) +#define MREPEAT191(macro, data) MREPEAT190(macro, data) macro(190, data) +#define MREPEAT192(macro, data) MREPEAT191(macro, data) macro(191, data) +#define MREPEAT193(macro, data) MREPEAT192(macro, data) macro(192, data) +#define MREPEAT194(macro, data) MREPEAT193(macro, data) macro(193, data) +#define MREPEAT195(macro, data) MREPEAT194(macro, data) macro(194, data) +#define MREPEAT196(macro, data) MREPEAT195(macro, data) macro(195, data) +#define MREPEAT197(macro, data) MREPEAT196(macro, data) macro(196, data) +#define MREPEAT198(macro, data) MREPEAT197(macro, data) macro(197, data) +#define MREPEAT199(macro, data) MREPEAT198(macro, data) macro(198, data) +#define MREPEAT200(macro, data) MREPEAT199(macro, data) macro(199, data) +#define MREPEAT201(macro, data) MREPEAT200(macro, data) macro(200, data) +#define MREPEAT202(macro, data) MREPEAT201(macro, data) macro(201, data) +#define MREPEAT203(macro, data) MREPEAT202(macro, data) macro(202, data) +#define MREPEAT204(macro, data) MREPEAT203(macro, data) macro(203, data) +#define MREPEAT205(macro, data) MREPEAT204(macro, data) macro(204, data) +#define MREPEAT206(macro, data) MREPEAT205(macro, data) macro(205, data) +#define MREPEAT207(macro, data) MREPEAT206(macro, data) macro(206, data) +#define MREPEAT208(macro, data) MREPEAT207(macro, data) macro(207, data) +#define MREPEAT209(macro, data) MREPEAT208(macro, data) macro(208, data) +#define MREPEAT210(macro, data) MREPEAT209(macro, data) macro(209, data) +#define MREPEAT211(macro, data) MREPEAT210(macro, data) macro(210, data) +#define MREPEAT212(macro, data) MREPEAT211(macro, data) macro(211, data) +#define MREPEAT213(macro, data) MREPEAT212(macro, data) macro(212, data) +#define MREPEAT214(macro, data) MREPEAT213(macro, data) macro(213, data) +#define MREPEAT215(macro, data) MREPEAT214(macro, data) macro(214, data) +#define MREPEAT216(macro, data) MREPEAT215(macro, data) macro(215, data) +#define MREPEAT217(macro, data) MREPEAT216(macro, data) macro(216, data) +#define MREPEAT218(macro, data) MREPEAT217(macro, data) macro(217, data) +#define MREPEAT219(macro, data) MREPEAT218(macro, data) macro(218, data) +#define MREPEAT220(macro, data) MREPEAT219(macro, data) macro(219, data) +#define MREPEAT221(macro, data) MREPEAT220(macro, data) macro(220, data) +#define MREPEAT222(macro, data) MREPEAT221(macro, data) macro(221, data) +#define MREPEAT223(macro, data) MREPEAT222(macro, data) macro(222, data) +#define MREPEAT224(macro, data) MREPEAT223(macro, data) macro(223, data) +#define MREPEAT225(macro, data) MREPEAT224(macro, data) macro(224, data) +#define MREPEAT226(macro, data) MREPEAT225(macro, data) macro(225, data) +#define MREPEAT227(macro, data) MREPEAT226(macro, data) macro(226, data) +#define MREPEAT228(macro, data) MREPEAT227(macro, data) macro(227, data) +#define MREPEAT229(macro, data) MREPEAT228(macro, data) macro(228, data) +#define MREPEAT230(macro, data) MREPEAT229(macro, data) macro(229, data) +#define MREPEAT231(macro, data) MREPEAT230(macro, data) macro(230, data) +#define MREPEAT232(macro, data) MREPEAT231(macro, data) macro(231, data) +#define MREPEAT233(macro, data) MREPEAT232(macro, data) macro(232, data) +#define MREPEAT234(macro, data) MREPEAT233(macro, data) macro(233, data) +#define MREPEAT235(macro, data) MREPEAT234(macro, data) macro(234, data) +#define MREPEAT236(macro, data) MREPEAT235(macro, data) macro(235, data) +#define MREPEAT237(macro, data) MREPEAT236(macro, data) macro(236, data) +#define MREPEAT238(macro, data) MREPEAT237(macro, data) macro(237, data) +#define MREPEAT239(macro, data) MREPEAT238(macro, data) macro(238, data) +#define MREPEAT240(macro, data) MREPEAT239(macro, data) macro(239, data) +#define MREPEAT241(macro, data) MREPEAT240(macro, data) macro(240, data) +#define MREPEAT242(macro, data) MREPEAT241(macro, data) macro(241, data) +#define MREPEAT243(macro, data) MREPEAT242(macro, data) macro(242, data) +#define MREPEAT244(macro, data) MREPEAT243(macro, data) macro(243, data) +#define MREPEAT245(macro, data) MREPEAT244(macro, data) macro(244, data) +#define MREPEAT246(macro, data) MREPEAT245(macro, data) macro(245, data) +#define MREPEAT247(macro, data) MREPEAT246(macro, data) macro(246, data) +#define MREPEAT248(macro, data) MREPEAT247(macro, data) macro(247, data) +#define MREPEAT249(macro, data) MREPEAT248(macro, data) macro(248, data) +#define MREPEAT250(macro, data) MREPEAT249(macro, data) macro(249, data) +#define MREPEAT251(macro, data) MREPEAT250(macro, data) macro(250, data) +#define MREPEAT252(macro, data) MREPEAT251(macro, data) macro(251, data) +#define MREPEAT253(macro, data) MREPEAT252(macro, data) macro(252, data) +#define MREPEAT254(macro, data) MREPEAT253(macro, data) macro(253, data) +#define MREPEAT255(macro, data) MREPEAT254(macro, data) macro(254, data) +#define MREPEAT256(macro, data) MREPEAT255(macro, data) macro(255, data) + +/** @} */ + +#endif /* _MREPEAT_H_ */ diff --git a/src/boards/mcu/samr34/ASF/sam0/utils/preprocessor/preprocessor.h b/src/boards/mcu/samr34/ASF/sam0/utils/preprocessor/preprocessor.h new file mode 100644 index 000000000..7e02523b3 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/utils/preprocessor/preprocessor.h @@ -0,0 +1,45 @@ +/** + * \file + * + * \brief Preprocessor utils. + * + * Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#ifndef _PREPROCESSOR_H_ +#define _PREPROCESSOR_H_ + +#include "tpaste.h" +#include "stringz.h" +#include "mrepeat.h" +#include "mrecursion.h" + +#endif // _PREPROCESSOR_H_ diff --git a/src/boards/mcu/samr34/ASF/sam0/utils/preprocessor/stringz.h b/src/boards/mcu/samr34/ASF/sam0/utils/preprocessor/stringz.h new file mode 100644 index 000000000..3de964a2e --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/utils/preprocessor/stringz.h @@ -0,0 +1,74 @@ +/** + * \file + * + * \brief Preprocessor stringizing utils. + * + * Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#ifndef _STRINGZ_H_ +#define _STRINGZ_H_ + +/** + * \defgroup group_sam0_utils_stringz Preprocessor - Stringize + * + * \ingroup group_sam0_utils + * + * @{ + */ + +/** \brief Stringize. + * + * Stringize a preprocessing token, this token being allowed to be \#defined. + * + * May be used only within macros with the token passed as an argument if the + * token is \#defined. + * + * For example, writing STRINGZ(PIN) within a macro \#defined by PIN_NAME(PIN) + * and invoked as PIN_NAME(PIN0) with PIN0 \#defined as A0 is equivalent to + * writing "A0". + */ +#define STRINGZ(x) #x + +/** \brief Absolute stringize. + * + * Stringize a preprocessing token, this token being allowed to be \#defined. + * + * No restriction of use if the token is \#defined. + * + * For example, writing ASTRINGZ(PIN0) anywhere with PIN0 \#defined as A0 is + * equivalent to writing "A0". + */ +#define ASTRINGZ(x) STRINGZ(x) + +/** @} */ + +#endif // _STRINGZ_H_ diff --git a/src/boards/mcu/samr34/ASF/sam0/utils/preprocessor/tpaste.h b/src/boards/mcu/samr34/ASF/sam0/utils/preprocessor/tpaste.h new file mode 100644 index 000000000..955533428 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/utils/preprocessor/tpaste.h @@ -0,0 +1,93 @@ +/** + * \file + * + * \brief Preprocessor token pasting utils. + * + * Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#ifndef _TPASTE_H_ +#define _TPASTE_H_ + +/** + * \defgroup group_sam0_utils_tpaste Preprocessor - Token Paste + * + * \ingroup group_sam0_utils + * + * @{ + */ + +/** \name Token Paste + * + * Paste N preprocessing tokens together, these tokens being allowed to be \#defined. + * + * May be used only within macros with the tokens passed as arguments if the tokens are \#defined. + * + * For example, writing TPASTE2(U, WIDTH) within a macro \#defined by + * UTYPE(WIDTH) and invoked as UTYPE(UL_WIDTH) with UL_WIDTH \#defined as 32 is + * equivalent to writing U32. + * + * @{ */ +#define TPASTE2( a, b) a##b +#define TPASTE3( a, b, c) a##b##c +#define TPASTE4( a, b, c, d) a##b##c##d +#define TPASTE5( a, b, c, d, e) a##b##c##d##e +#define TPASTE6( a, b, c, d, e, f) a##b##c##d##e##f +#define TPASTE7( a, b, c, d, e, f, g) a##b##c##d##e##f##g +#define TPASTE8( a, b, c, d, e, f, g, h) a##b##c##d##e##f##g##h +#define TPASTE9( a, b, c, d, e, f, g, h, i) a##b##c##d##e##f##g##h##i +#define TPASTE10(a, b, c, d, e, f, g, h, i, j) a##b##c##d##e##f##g##h##i##j +/** @} */ + +/** \name Absolute Token Paste + * + * Paste N preprocessing tokens together, these tokens being allowed to be \#defined. + * + * No restriction of use if the tokens are \#defined. + * + * For example, writing ATPASTE2(U, UL_WIDTH) anywhere with UL_WIDTH \#defined + * as 32 is equivalent to writing U32. + * + * @{ */ +#define ATPASTE2( a, b) TPASTE2( a, b) +#define ATPASTE3( a, b, c) TPASTE3( a, b, c) +#define ATPASTE4( a, b, c, d) TPASTE4( a, b, c, d) +#define ATPASTE5( a, b, c, d, e) TPASTE5( a, b, c, d, e) +#define ATPASTE6( a, b, c, d, e, f) TPASTE6( a, b, c, d, e, f) +#define ATPASTE7( a, b, c, d, e, f, g) TPASTE7( a, b, c, d, e, f, g) +#define ATPASTE8( a, b, c, d, e, f, g, h) TPASTE8( a, b, c, d, e, f, g, h) +#define ATPASTE9( a, b, c, d, e, f, g, h, i) TPASTE9( a, b, c, d, e, f, g, h, i) +#define ATPASTE10(a, b, c, d, e, f, g, h, i, j) TPASTE10(a, b, c, d, e, f, g, h, i, j) +/** @} */ + +/** @} */ + +#endif // _TPASTE_H_ diff --git a/src/boards/mcu/samr34/ASF/sam0/utils/status_codes.h b/src/boards/mcu/samr34/ASF/sam0/utils/status_codes.h new file mode 100644 index 000000000..5f2769ef7 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/utils/status_codes.h @@ -0,0 +1,148 @@ +/** + * \file + * + * \brief Status code definitions. + * + * This file defines various status codes returned by functions, + * indicating success or failure as well as what kind of failure. + * + * Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#ifndef STATUS_CODES_H_INCLUDED +#define STATUS_CODES_H_INCLUDED + +#include + +/** + * \defgroup group_sam0_utils_status_codes Status Codes + * + * \ingroup group_sam0_utils + * + * @{ + */ + +/** Mask to retrieve the error category of a status code. */ +#define STATUS_CATEGORY_MASK 0xF0 + +/** Mask to retrieve the error code within the category of a status code. */ +#define STATUS_ERROR_MASK 0x0F + +/** Status code error categories. */ +enum status_categories { + STATUS_CATEGORY_OK = 0x00, + STATUS_CATEGORY_COMMON = 0x10, + STATUS_CATEGORY_ANALOG = 0x30, + STATUS_CATEGORY_COM = 0x40, + STATUS_CATEGORY_IO = 0x50, +}; + +/** + * Status code that may be returned by shell commands and protocol + * implementations. + * + * \note Any change to these status codes and the corresponding + * message strings is strictly forbidden. New codes can be added, + * however, but make sure that any message string tables are updated + * at the same time. + */ +enum status_code { + STATUS_OK = STATUS_CATEGORY_OK | 0x00, + STATUS_VALID_DATA = STATUS_CATEGORY_OK | 0x01, + STATUS_NO_CHANGE = STATUS_CATEGORY_OK | 0x02, + STATUS_ABORTED = STATUS_CATEGORY_OK | 0x04, + STATUS_BUSY = STATUS_CATEGORY_OK | 0x05, + STATUS_SUSPEND = STATUS_CATEGORY_OK | 0x06, + + STATUS_ERR_IO = STATUS_CATEGORY_COMMON | 0x00, + STATUS_ERR_REQ_FLUSHED = STATUS_CATEGORY_COMMON | 0x01, + STATUS_ERR_TIMEOUT = STATUS_CATEGORY_COMMON | 0x02, + STATUS_ERR_BAD_DATA = STATUS_CATEGORY_COMMON | 0x03, + STATUS_ERR_NOT_FOUND = STATUS_CATEGORY_COMMON | 0x04, + STATUS_ERR_UNSUPPORTED_DEV = STATUS_CATEGORY_COMMON | 0x05, + STATUS_ERR_NO_MEMORY = STATUS_CATEGORY_COMMON | 0x06, + STATUS_ERR_INVALID_ARG = STATUS_CATEGORY_COMMON | 0x07, + STATUS_ERR_BAD_ADDRESS = STATUS_CATEGORY_COMMON | 0x08, + STATUS_ERR_BAD_FORMAT = STATUS_CATEGORY_COMMON | 0x0A, + STATUS_ERR_BAD_FRQ = STATUS_CATEGORY_COMMON | 0x0B, + STATUS_ERR_DENIED = STATUS_CATEGORY_COMMON | 0x0c, + STATUS_ERR_ALREADY_INITIALIZED = STATUS_CATEGORY_COMMON | 0x0d, + STATUS_ERR_OVERFLOW = STATUS_CATEGORY_COMMON | 0x0e, + STATUS_ERR_NOT_INITIALIZED = STATUS_CATEGORY_COMMON | 0x0f, + + STATUS_ERR_SAMPLERATE_UNAVAILABLE = STATUS_CATEGORY_ANALOG | 0x00, + STATUS_ERR_RESOLUTION_UNAVAILABLE = STATUS_CATEGORY_ANALOG | 0x01, + + STATUS_ERR_BAUDRATE_UNAVAILABLE = STATUS_CATEGORY_COM | 0x00, + STATUS_ERR_PACKET_COLLISION = STATUS_CATEGORY_COM | 0x01, + STATUS_ERR_PROTOCOL = STATUS_CATEGORY_COM | 0x02, + + STATUS_ERR_PIN_MUX_INVALID = STATUS_CATEGORY_IO | 0x00, +}; +typedef enum status_code status_code_genare_t; + +/** + Status codes used by MAC stack. + */ +enum status_code_wireless { + //STATUS_OK = 0, //!< Success + ERR_IO_ERROR = -1, //!< I/O error + ERR_FLUSHED = -2, //!< Request flushed from queue + ERR_TIMEOUT = -3, //!< Operation timed out + ERR_BAD_DATA = -4, //!< Data integrity check failed + ERR_PROTOCOL = -5, //!< Protocol error + ERR_UNSUPPORTED_DEV = -6, //!< Unsupported device + ERR_NO_MEMORY = -7, //!< Insufficient memory + ERR_INVALID_ARG = -8, //!< Invalid argument + ERR_BAD_ADDRESS = -9, //!< Bad address + ERR_BUSY = -10, //!< Resource is busy + ERR_BAD_FORMAT = -11, //!< Data format not recognized + ERR_NO_TIMER = -12, //!< No timer available + ERR_TIMER_ALREADY_RUNNING = -13, //!< Timer already running + ERR_TIMER_NOT_RUNNING = -14, //!< Timer not running + + /** + * \brief Operation in progress + * + * This status code is for driver-internal use when an operation + * is currently being performed. + * + * \note Drivers should never return this status code to any + * callers. It is strictly for internal use. + */ + OPERATION_IN_PROGRESS = -128, +}; + +typedef enum status_code_wireless status_code_t; + +/** @} */ + +#endif /* STATUS_CODES_H_INCLUDED */ diff --git a/src/boards/mcu/samr34/ASF/sam0/utils/stdio/read.c b/src/boards/mcu/samr34/ASF/sam0/utils/stdio/read.c new file mode 100644 index 000000000..58053dc33 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/utils/stdio/read.c @@ -0,0 +1,152 @@ +/** + * \file + * + * \brief System-specific implementation of the \ref _read function used by + * the standard library. + * + * Copyright (c) 2009-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#include "compiler.h" + +/** + * \defgroup group_common_utils_stdio Standard I/O (stdio) + * + * Common standard I/O driver that implements the stdio + * read and write functions on AVR and SAM devices. + * + * \{ + */ + +extern volatile void *volatile stdio_base; +void (*ptr_get)(void volatile*, char*); + + +// IAR common implementation +#if ( defined(__ICCARM__) ) + +#include + +#if (__VER__ < 8010000) +// Refer http://ftp.iar.se/WWWfiles/arm/webic/doc/EWARM_MigrationGuide.ENU.pdf +_STD_BEGIN +#endif + +#pragma module_name = "?__read" + +/*! \brief Reads a number of bytes, at most \a size, into the memory area + * pointed to by \a buffer. + * + * \param handle File handle to read from. + * \param buffer Pointer to buffer to write read bytes to. + * \param size Number of bytes to read. + * + * \return The number of bytes read, \c 0 at the end of the file, or + * \c _LLIO_ERROR on failure. + */ +size_t __read(int handle, unsigned char *buffer, size_t size) +{ + int nChars = 0; + // This implementation only reads from stdin. + // For all other file handles, it returns failure. + if (handle != _LLIO_STDIN) { + return _LLIO_ERROR; + } + for (; size > 0; --size) { + ptr_get(stdio_base, (char*)buffer); + buffer++; + nChars++; + } + return nChars; +} + +/*! \brief This routine is required by IAR DLIB library since EWAVR V6.10 + * the implementation is empty to be compatible with old IAR version. + */ +int __close(int handle) +{ + UNUSED(handle); + return 0; +} + +/*! \brief This routine is required by IAR DLIB library since EWAVR V6.10 + * the implementation is empty to be compatible with old IAR version. + */ +int remove(const char* val) +{ + UNUSED(val); + return 0; +} + +/*! \brief This routine is required by IAR DLIB library since EWAVR V6.10 + * the implementation is empty to be compatible with old IAR version. + */ +long __lseek(int handle, long val, int val2) +{ + UNUSED(handle); + UNUSED(val2); + return val; +} + +#if (__VER__ < 8010000) +// Refer http://ftp.iar.se/WWWfiles/arm/webic/doc/EWARM_MigrationGuide.ENU.pdf +_STD_END +#endif + +// GCC implementation +#elif (defined(__GNUC__)) + +int __attribute__((weak)) +_read (int file, char * ptr, int len); // Remove GCC compiler warning + +int __attribute__((weak)) +_read (int file, char * ptr, int len) +{ + int nChars = 0; + + if (file != 0) { + return -1; + } + + for (; len > 0; --len) { + ptr_get(stdio_base, ptr); + ptr++; + nChars++; + } + return nChars; +} + +#endif + +/** + * \} + */ + diff --git a/src/boards/mcu/samr34/ASF/sam0/utils/stdio/stdio_serial/stdio_serial.h b/src/boards/mcu/samr34/ASF/sam0/utils/stdio/stdio_serial/stdio_serial.h new file mode 100644 index 000000000..b9d3874bd --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/utils/stdio/stdio_serial/stdio_serial.h @@ -0,0 +1,140 @@ +/** + * + * \file + * + * \brief Common Standard I/O Serial Management. + * + * This file defines a useful set of functions for the Stdio Serial interface on + * SAM0 devices. + * + * Copyright (c) 2009-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + ******************************************************************************/ +/* + * Support and FAQ: visit Microchip Support + */ + + +#ifndef STDIO_SERIAL_H_INCLUDED +#define STDIO_SERIAL_H_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup group_common_utils_stdio_stdio_serial Standard serial I/O (stdio) + * \ingroup group_common_utils_stdio + * + * Common standard serial I/O management driver that + * implements a stdio serial interface on AVR and SAM devices. + * + * @{ + */ + +#include +#include +#include + +/** Pointer to the base of the USART module instance to use for stdio. */ +extern volatile void *volatile stdio_base; + +/** Pointer to the external low level write function. */ +extern int (*ptr_put)(void volatile*, char); + +/** Pointer to the external low level read function. */ +extern void (*ptr_get)(void volatile*, char*); + +#if SAM0 +/** \brief Initializes the stdio in Serial Mode. + * + * \param module Software USART instance to associate with the hardware. + * \param hw Base address of the USART hardware instance. + * \param config USART configuration parameters for the STDIO stream. + * + */ +static inline void stdio_serial_init( + struct usart_module *const module, + usart_inst_t const hw, + const struct usart_config *const config) +{ + stdio_base = (void *)module; + ptr_put = (int (*)(void volatile*,char))&usart_serial_putchar; + ptr_get = (void (*)(void volatile*,char*))&usart_serial_getchar; + + usart_serial_init(module, hw, config); +# if defined(__GNUC__) + // Specify that stdout and stdin should not be buffered. + setbuf(stdout, NULL); + setbuf(stdin, NULL); + // Note: Already the case in IAR's Normal DLIB default configuration + // and AVR GCC library: + // - printf() emits one character at a time. + // - getchar() requests only 1 byte to exit. +# endif +} +#endif + +#if SAMB +/** \brief Initializes the stdio in Serial Mode. + * + * \param module Software UART instance to associate with the hardware. + * \param hw Base address of the UART hardware instance. + * \param config UART configuration parameters for the STDIO stream. + * + */ +static inline void stdio_serial_init( + struct uart_module *const module, + Uart * const hw, + const struct uart_config *const config) +{ + stdio_base = (void *)module; + ptr_put = (int (*)(void volatile*,char))&usart_serial_putchar; + ptr_get = (void (*)(void volatile*,char*))&usart_serial_getchar; + + usart_serial_init(module, hw, config); +# if defined(__GNUC__) + // Specify that stdout and stdin should not be buffered. + setbuf(stdout, NULL); + setbuf(stdin, NULL); + // Note: Already the case in IAR's Normal DLIB default configuration + // and AVR GCC library: + // - printf() emits one character at a time. + // - getchar() requests only 1 byte to exit. +# endif +} +#endif + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif // _STDIO_SERIAL_H_ diff --git a/src/boards/mcu/samr34/ASF/sam0/utils/stdio/write.c b/src/boards/mcu/samr34/ASF/sam0/utils/stdio/write.c new file mode 100644 index 000000000..30bdaafc4 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/utils/stdio/write.c @@ -0,0 +1,132 @@ +/** + * \file + * + * \brief System-specific implementation of the \ref _write function used by + * the standard library. + * + * Copyright (c) 2009-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#include "compiler.h" + +/** + * \addtogroup group_common_utils_stdio + * + * \{ + */ + +volatile void *volatile stdio_base; +int (*ptr_put)(void volatile*, char); + + +#if ( defined(__ICCARM__)) + +#include + +#if (__VER__ < 8010000) +// Refer http://ftp.iar.se/WWWfiles/arm/webic/doc/EWARM_MigrationGuide.ENU.pdf +_STD_BEGIN +#endif + +#pragma module_name = "?__write" + +/*! \brief Writes a number of bytes, at most \a size, from the memory area + * pointed to by \a buffer. + * + * If \a buffer is zero then \ref __write performs flushing of internal buffers, + * if any. In this case, \a handle can be \c -1 to indicate that all handles + * should be flushed. + * + * \param handle File handle to write to. + * \param buffer Pointer to buffer to read bytes to write from. + * \param size Number of bytes to write. + * + * \return The number of bytes written, or \c _LLIO_ERROR on failure. + */ +size_t __write(int handle, const unsigned char *buffer, size_t size) +{ + size_t nChars = 0; + + if (buffer == 0) { + // This means that we should flush internal buffers. + return 0; + } + + // This implementation only writes to stdout and stderr. + // For all other file handles, it returns failure. + if (handle != _LLIO_STDOUT && handle != _LLIO_STDERR) { + return _LLIO_ERROR; + } + + for (; size != 0; --size) { + if (ptr_put(stdio_base, *buffer++) < 0) { + return _LLIO_ERROR; + } + ++nChars; + } + return nChars; +} + +#if (__VER__ < 8010000) +// Refer http://ftp.iar.se/WWWfiles/arm/webic/doc/EWARM_MigrationGuide.ENU.pdf +_STD_END +#endif + + +#elif (defined(__GNUC__)) + +int __attribute__((weak)) +_write (int file, char * ptr, int len); + +int __attribute__((weak)) +_write (int file, char * ptr, int len) +{ + int nChars = 0; + + if ((file != 1) && (file != 2) && (file!=3)) { + return -1; + } + + for (; len != 0; --len) { + if (ptr_put(stdio_base, *ptr++) < 0) { + return -1; + } + ++nChars; + } + return nChars; +} + +#endif + +/** + * \} + */ + diff --git a/src/boards/mcu/samr34/ASF/sam0/utils/syscalls/gcc/syscalls.c b/src/boards/mcu/samr34/ASF/sam0/utils/syscalls/gcc/syscalls.c new file mode 100644 index 000000000..ef46ff199 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/sam0/utils/syscalls/gcc/syscalls.c @@ -0,0 +1,120 @@ +/** + * \file + * + * \brief Syscalls for SAM0 (GCC). + * + * Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#undef errno +extern int errno; +extern int _end; + +extern caddr_t _sbrk(int incr); +extern int link(char *old, char *new); +extern int _close(int file); +extern int _fstat(int file, struct stat *st); +extern int _isatty(int file); +extern int _lseek(int file, int ptr, int dir); +extern void _exit(int status); +extern void _kill(int pid, int sig); +extern int _getpid(void); + +extern caddr_t _sbrk(int incr) +{ + static unsigned char *heap = NULL; + unsigned char *prev_heap; + + if (heap == NULL) { + heap = (unsigned char *)&_end; + } + prev_heap = heap; + + heap += incr; + + return (caddr_t) prev_heap; +} + +extern int link(char *old, char *new) +{ + return -1; +} + +extern int _close(int file) +{ + return -1; +} + +extern int _fstat(int file, struct stat *st) +{ + st->st_mode = S_IFCHR; + + return 0; +} + +extern int _isatty(int file) +{ + return 1; +} + +extern int _lseek(int file, int ptr, int dir) +{ + return 0; +} + +extern void _exit(int status) +{ + asm("BKPT #0"); + for (;;); +} + +extern void _kill(int pid, int sig) +{ + return; +} + +extern int _getpid(void) +{ + return -1; +} + +#ifdef __cplusplus +} +#endif diff --git a/src/boards/mcu/samr34/ASF/thirdparty/CMSIS/ATMEL-disclaimer.txt b/src/boards/mcu/samr34/ASF/thirdparty/CMSIS/ATMEL-disclaimer.txt new file mode 100644 index 000000000..ad0f942c5 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/thirdparty/CMSIS/ATMEL-disclaimer.txt @@ -0,0 +1,20 @@ +/* + * Only the CMSIS required parts for ASF are included here, go to the below + * address for the full package: + * http://www.arm.com/products/processors/cortex-m/cortex-microcontroller-software-interface-standard.php + * + * The library file thirdparty/CMSIS/Lib/GCC/libarm_cortexM4lf_math_softfp.a was generated by ATMEL, which + * is support -mfloat-abi=softfp compiler flag, and this is also the default selection for device that + * have FPU module and enabled. + * If customer want to use -mfloat-abi=hard compiler flag, the project compile/link flag and link library + * should be manual modified. The library thirdparty/CMSIS/Lib/GCC/libarm_cortexM4lf_math.a is used for + * -mfloat-abi=hard configration. + * + * __CORTEX_SC is not defined for cortex-m0+, and may cause compiler warning, so the include file + * thirdparty/CMSIS/Include/core_cmInstr.h was modified to void such warning. + * Modified from: + * #if (__CORTEX_M >= 0x03) || (__CORTEX_SC >= 300) + * to: + * #if (__CORTEX_M >= 0x03) || ((defined(__CORTEX_SC)) && (__CORTEX_SC >= 300)) + * + */ diff --git a/src/boards/mcu/samr34/ASF/thirdparty/CMSIS/CMSIS_END_USER_LICENCE_AGREEMENT.pdf b/src/boards/mcu/samr34/ASF/thirdparty/CMSIS/CMSIS_END_USER_LICENCE_AGREEMENT.pdf new file mode 100644 index 0000000000000000000000000000000000000000..c67c8672dbf9fdcf4bf64a22791e24c9f1688d1d GIT binary patch literal 179946 zcmdSARdgK7vaTzzm@Q_qn3*kRvY1&dW@gD2Gcz+<%*@QpXfZQOSN7a2IbP5i3js^~jb^w69wY38QBg>yI(t390 z;#Nl1A7*|Z0t^X0x&gj^eBht~R)&9E{5JM)zW(^26SQ`;av)%#lQcE7*C1f}ZH|C} z`LBlcuZI0k!$|+T(IWV#&EMVs!{�JHUs{ztqbE?5!Q`3;^~Y+C;3a9DX+p1b@jE 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

-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

4@+o^W>VaQIc%93|-p(KNG*_h^!tqtqn=-d=u+P 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

45<* zG57caucRC+ux_Os>#^LWs}wB)0(wqR*XU?AZqDQuX8kb;){qfVvbtAwXS{9wyq+ zqzwVu(FCIcEdJcR*bQ@_O_EU>mQEgzB%`o%)mcJ22eYqX?UBBlyKU48F{mK%rv z8-y6J{}CWj*@ZzwUk7fB@)GBt^<1%1uKmq_8K#k5weSywMPDiaRQxj~# zI!*=-0U(9#V2+Tdes&#sH$s|9=sE&7LPi(Sv=bncQ-1#o18f9NQRNCc@C?safmi~l zG2|)7XaR9W4-{ZBa5w-ntXHMd5fFl9$}s*3JdRcRjV9~h2N}L}yd+1U1Q$hj-Kxff@uAI4t&_|^8W z)sGO-UIR>s+!e-n#MTA$_@#+Y)SedD09{awsg1%bHBu2>Q2GjX{2jP&;F5JvP^Knp z51r0Cd5@G$Na_k|{26eIe*JS765srN&ko!ib|XHS9|Rt+N%&<4em|Z8aR0ch;PQD~ zA8Y`abkM)lp&eudaI4JA1Gq7kMO*~OT>-Ng$D~c6fqL@FehMzw33}2laN~C1p`uRH z_~!UM3~)rz5gEvdbR15#E@ICId>J-Mxged%Pctii#ST6OEQZxds67921{Y2Lst&IM zs2qxzqi5jBUkC8z6!Apf76w@mD)TER7yc0a zUieT1C>x)`S3-ibrW&IHOMq(uZ=115A4XZQwlu03A+AeTE@^WXWp=5}2@n?KU>HAPnU^&S&-edU{ z!BU*d3c*q+Ifj}cnl|Q549yt(#D|IMiHQ%@yl4@Be%{l2b$>1pLgjg_!3d<%TuJn) z^mG{?q^*$S!%cENvDbb~lT}%k4F0+Lt{_m7rGTkmq~yX(S$Y~wl0@NJ0bBI82&V`e zK63SF5^zx^ng72)ZPTe<=#g9BU+ z#|5seiTlI*VE7;`rB?aE`e6DX`k+3D2DBF*<8F&0J|p_PAq#qvSg)jiK>Op5C<62R zrX^Py`fMs5{2;uJ)d3B3Hx@+pL-HW?K)d7Zw1=sLZ-+NwQY1-uIiFSoiBvfres*HL`bJv&U+N!g~dH8@D4hk(#^b+fdr5B(jG#?rB%FBFh#%h_n_W}DM^R|oOtZLeO)w5hZEV|$t1;9h7S zT-n{|XCDsrGiNMS9X(gPDqmVUooXzu3tw{0ZMbMXY5ATVXSat6bZ;m<5%8WT{8N8| zai?YJSi*^ia!@QOjwFGK<_J`RKKs6(Tj!{9R~^`35}cXa1get2%}XD)nQAYCF2BE;aU7tBJm)Q5v@zr}`VEOux>u-@NQd4g0jU4*Tp# z$@$3Lu$(h9= zMO}lgCIilKPe-e9AjhCG=P?G`5v5MaZGaZ{_mf% zFWZZbkUXZs_fo65EHW~F$l?3S=~k7=ZynI|nDzmE^}p>7GRw*DME*QgE1J$8(w^-6 z9+&9yGmg*Dfgv(dh`pLu<(#%ln7uPQFCuRBO*XIbNKcJq_)>mEoIyAXIZy3WRjf zu5%etSHWswxxgF+xV=NKgDr+D|AaP<&IKFOp|g(n4w(z)>JvFOjCCMM9?2QJdIyOS zw*yBNsuoHa3_~F5`UfNab@&w6osO@sSNjrayQ~PHaH?oboekh z@Fz^RH)k+(Fbe^wO@W;q?~LB9!_@@Hzk~mbG#Q}w4uJ^f1N@f&+|O@tV33TEYy$AB zU;rI&h+yIKawkAa}_M7ZTVgFT~L_g#;BJ@9}sU=1D$hZN`@&=}Ylz#GULFc-K6TM1hU*N)%^ z-vakY;z8_z;_=o4)`P+W(}Um^{|x<1Zry7AaP!z`4UT!Z*Tt2O7dO!ZpJ1!t=uN!tuhqHYc!iaNYsH zfYQKRcuiPMI8B)5z~R8*0J%W908k((04)$LK)>Uz!?Oe2p=g9Oj_`;+k7)zn0Jm4Q zNSsafkZbzleC!|lG*e=XYoyf^>y|88Dj2XF>#p|A77^Nqs9{$G{<>jhT#<{!ws zb4{Vn$G)+xW7RkO*CPFYnW9(xkM=nX{)dQ>a_Ci5n`=G~1)0 z#(6>N`0X`fDL^;RtycJ$){PNVC9}Y~Q2H`d8A7>WWNG5I(mFDL$Ts`n3eBhHg%u79 z@k;@HBhAx{)A7n~r6jj_*dLH;9iGfst+|>Z)x#$`%pV{|~hz5LeT)xw# zq4jX@2>>THr2-*XuXMb?yC(79pw31{fg+FLYN-a=~Z$^RYPPXUdbeJ1i6T z{?m*8YJLL@{ae5MsGW;aa1T9>ZVu!Y#;V~fdy9$G^DBaBU1NScELEOftQ784TJTnp zvJ>(GWjVC%g4)tof?A)@8d6un_DW7GBcMi&Ku$vA6{ex<>SngYn<{VZIKWGO4YURd zS}62Qd6<7XhAsORzTlU|6}J(e5^m)E0U(^WK>tGIP3E~F1*Th2<;%}8ZZ{dLA)Ln@ z5U%tUiCG36n_mO38Qed$_B=u-mmrw|ww*WBLPBe=6K?D841|}GC+3gnA=Bt(F|2&{>UE3AskJ)gR1IC%*HtiYK`>jb+p%*bs1~jirG6%*u6Yc zaaZ8Y1_4hmyX`6c+SbpO!V~E5$u<$}TOY2QN0oAvGSrlBPZ^=H#E`_AM6T~2=xJ4> zCY;6FIQ%S6L%O=Er;^UMoP_B<&}Y~#heS@fgqk8T{>HOP{}CZH*ZO#Zx>C?Bz2h== zxf2@JsU7(dvrvpUEndjlI=0rwe02Izj5d3)gfmT{n|4&l*ueAvr7|-CvFHbeEKg=4 zQc)46EC;z?_qVgFH4KzByd%#(T7s~J=O#??Do;mx z5`c$>ZXrCmOrV9^H7|mljXT+d+@OQ6x%>ubN+IpQ&s^6S{ScBN;V-^@jwXtTj0Y{>OsPWTxp&i5m(vdx;75ky#j}}R zm1Pgt@iLvv2zZN2(uogYrao&13wV7F3w0;D)zD25tW47<+O~_;^Kw4p0LAk;J*al$l9ROT~Yo%m)@GFPfy9g(=Gh@ThErJ z_y@X1PghP!^H35Oo7C$Tgl5gzVro~O}q9#s`8M9%9-b}e4n(`y^zy*lL)7 zSYzipe|C3ifBbU(+N=CQDT9kV^A6^|GA4)!o`Mv9LP@pV9G5gu&Gv>QITOFI*G7?& z>jSs*7S0vIx$7n(dfZMME;s^^qM1AJpQf=cH6FmFi94u z^zF)|;A2HUQ*cDa2(c|B^+0~+1hOdo;_po0A334OF|Ia4cW(|i*YRjxV9_z=Jvwcq zTf&g`PI$`vvf#;*2}w@P7G{_N43mXcx0l_ZJ;ofrtF6AY0~{Z$_+ufiT22^W=4>H& z#>En6Q)4#kWdXJ5Tfjz((>{Sev=Q!#0&d-N1zlW+@Wb2|NHtHH_Lwer!PQURxWJYJ zJ~^FVHNE@tN{XYOxqj%X)=Y8Ms4_hcG?>~HI=kwcyWgUHB`0<+gB(oTh0i^YdA#n; zy0E`^JokSoEQ=LAr+a?cy8eAzA*w!L?4^Qs2Wm9TXi!%TSvAOZn&P-S@w@(`Iij*sIW2 zLehAyYcuBsR=U!7YTqtGr|}oN)K&u18W_CqA8l>Gr>$uXwQuhS*-w;N=HznU%vwG+ zKzaFJ5Ap8dvY?&9XD??k>2*S*^m@h2UwEsL-cl&jCeox&7ZbCOzv;^Y|l8a_4vTWNSkzguN}nc_?Q;YeE! z-ILgofBhoGE%}VTbgmdqD-w%IuK&oCzY@QJ(#=1Gf&-GPhAnkkeZ-hn#CYA9RLn?dO+=Qf z2H0LS0?rPV_+c|E!-_rzMO49pF-zE1i>%jt%fswKDu303$?Jjj(Aim_ijIj&_nBo> ztExxIzA5N>G~k+CXCjqf$MDGL9JqFZZq=&HeGP2IgBJNs=b3#c0Dr0FvVQwSL|rr7 z$n{>akjJFFT7##1@_TEtNt9pML;a_gYV{+~<0)$lPrZK2PXy{b>ou?PIqCN$zGLb> z{(NOSl5yR>7hL_cWT$7&@DCtA@DV{%s8=NA+MFnwJ(N+85Qz)P4;`wuZhw>LE#uTX;s{ zvesG+-N;R5;KS~xScv;c>;3$1yORq7##BHH@iVOL$w;^i2I-HO1Bcsb>vMpWt8U$` zu~7NG3~UbO$>7}ebTxE1PKq^PHLtwGt9+*XwcIt>Osd&_Peivr}W`Wt&herkSSs!yJ)m?@jNZr@kPV~stt znRbISscXEIWho!?ETRF0yQy2AQ53FBF+ zO2GOTlAv#qbK6qSG|-CbC~w(^5~yb^l6H4$gxJ{GqlT<65Fi6#7pG^H(H5CAV)kQV zn8~f-Nh%OCb)LA5x#!Emq(sL#)Ko}=As(7?**fH9b8u6juD~l}HOvZ(?b2#HOk35= zM+oV3hMP;yBDr1113bC)KwMi$&^`~tedhGF#yN>(S$Gk1)7#Sx0vF5d{RG34v+#_4 zeUmgG$>V!2ChQ?Yk`jCS%kX=EQH{@)6FTPa!q~A~Esv4BaEa%|Pl=*+8ke8ycK45G zOv`jb!9Nhl?J*G-|Lir+prLWT46T!>V;NZY+V6E4b9~Q!_0ygR|z_XC*G-)-Lu07Dyy=QVNU;=A*}-> z-|vonvidx1iF#X#(NNE`iC|KuBO%5&-N86cHmbSP ztee3e-yPIF^GUV7#Dz<(*5!GW!0OcGqlwO9SH2NOd1_lD$ehYlVSDWcJ6FiQ9> z4q9_VQ6adxckQLfvNl&IDpJOsy-&O@Tz9FP=-Rb2BjC&mnX7?fE}xQ+$ZnVfM<`-`=E^*yhOnd5RMgYq@0s25@*{9$Eb|6#W*VyQ7f!=)rr$y%=Z3+)XeX ztMaz`88dvh{i*++j@J5FSaf#nVER$?)&26N%W&{Dg-7gYmwc!^PCIv}++cmaw!(V} zCCdqIS3fb+{taf5(d_K&DvgLVRPrnH|04RLcI&;Ki}mvJEF-c8+<%ulHzrE{3_hbo zdm%o{h^e9JziXcw6UBY*-VmjDE;`GI<5;VH_R$mdCw!FY^2d4X^_R0m8PXuzTWc2% zUN?k!!QE&_HW*gXpqY(d7=g_8Q?|dgy0NPb%v1ne+@E|tiV?7zraZ~?0)Iq_gZv=bvE{yY{FHsGhS)CHy?DDnRQiZH8o z0{Mzg)~^Cv39ZKzg*2!eGp@XRJ@ytXa$7lVCY@E8w2G4%H6#q{6hoa6I9EbFvHm-P#d1+(uoz?}O$R?~@gHj=&2aI6WoX+9tUjR7oLudlJss?G_K^8XL0VmJUop#spjwudUo8l-6@ zNg9J~@2`a4m_}>=@T~g~IenWh#pjUd!s1}d!oKNew)R(H27Rqg;lCV{_1xx?vUFDgGqm1d4kk* zXk#Dg0`(?BwbU_AbMIS~_lL|H@kY{z(K4l|TlR9OS6?A72)w)RhD&z0wvIC6+ClZd zB-&=Zbjk}0^s?Npxmi!st=Bj0% zlh8fY-0if_iZ{5#eQR4K7sy{R>H!h;v*oiU=Rf`k?zk6>H%worAUE7CJ~v5yX<PQNtJ3YN>= zBwbF#rNGHrO-5?akgy_%ekDopZb2cR;c38Y1%G#Wi04S-pt?%dFb6ubL-o|Yx)<%%CrOaUsw$Ec6`u6V4z0(2 zB!6)As!?CCOj!}tK^5T6X3SOE(N`IB$|?yY2jRH3)~9$X!8+LALm-3 zK>Ce`_vEVXL>k<5RhKQQk)f;f0MwCc;mTs|tNhNL-kxmha4>C9s53NeFr_=R?2#@r zc*)&mA|`>Fag_X>J){!gvCx5?n*&h^N~N{LvZi{YBr|uOCSt7_y&D z1x^G`h&6}}27g8J75_*kl#;;ias6#>lg7dP`mC+HRJz6C3VCQgK3is#BHa^G;c<7F z(K?40OY#W}n7*Ho>7R%ESx#F4@C#laRzrJ-WlTq%o>%8}F3Q}pT(ew{y|)l!{M{al z=P=qF33lcoH*ua7cUH0W5G4f?pb)Rs;dV}9xFUt1=R;B(U@(nij454pR>?DFY~xxvcoBKx59$HA16d}Vq(yEC**yIuB9z0vThbZSI|_v{ zgQMAeHR%ANmvyJJJ35k(EUfwLv?IePr@>S1RC(BRn4vybnbB;$^ebToUPDRCckd8V z>Ru-DTgTt>QKFRMo@+RVTLkDhi=^#cJ6ds2v-`}wG+P3cDTnAaa|&*)ji^)V3sLIx zEt#>38b*75cz|3Kc_QBNn%e*Ar9SO)oXk296*$Vu^wdd4+lxJJ-2<@;ni1x(LN0>X z!y8s6Jnf5PM!Jhkf$7{3{&^vewT9Que=;X)upcMW@i=~6sT@u$s5!qEAzf&8H z$OX?J{udt68BWh({;TNHK0O-|UF&7u+&IS1&6G6RMzm|&Ahci!<1wG-`cylvR&P~0SS$BWz-W7ZL zfgT332GA{=cpA;!g!bs2_4WoA@TFreC~h)x^yBr#fPJbM%fp{b_qm_K`8$QQUiVHt z#d|hfwcK~}bBj1bxodxV5@dVXJ#+24R-BbCSTDL&$V0OnuOcob$Za7DyVsTUzrMR1Sqiqpaa$BsH>4{qMbniuH=9N|_BWXbnd>PXq^LQty#9p09Q2{4 znN0Jx@fr%Z$2J&ziD^qK1^BGk)I0qc@9I6;?nBe)54s&n^QyR6wzqzE-MT3@bKzU{ zgnI&i@|ED0FwL^&HW{;87Q(^c&g3kb)4R;EX|kf9;HSRApMsu*@s>+pmDFYTc-e(A z+t_jIo@8a0^AK(kMw?b1gfaFt?#gqi#9op1*8iynqsL7Hq0(lRts(}owARmHzyva z=trwGC=4r#3NSCtccxh^Z9Zh}LYL+d)QL2s$zxPlg$+i?$G$q-_tfsL*!Ed0D(0*L zj(?;v-~XWGzR^!VPcSw(03QDysg1rY>}$bmmoeVsNovigmf$=r=WSOR@m&;m7VWRy zRV+7e=b%kM3h%S}r#LWz%(HQ@sY8EA{5FsMT)WIHlmafu-hrKnrIR_^<}+`546hnjEUG#$%d}Yf3%HQ$E+KVl z947ZDyJcwa6Y+9;(nG6dDVD8g$rHm9Kdqk6l9d0_N34lBraQuWLD`>4?dpmV`LbH* zs#GR6^t91tX*^CiDO6Q5y`ISDx<#VLw&({TB=J9Um{DDS@fY^wpDA>lqeT6v8Se8 zdT=IVxnHW>IxqjiE)DIbgJVKiEMfxX zXF+p%Gu_~k_AIH%07Uvff23$i{SDMbp72nlwo$}9kKNb%jH-j^@tetsCXdXZkF z9Gt4P@}{3XPkvv=@lAuJIJMvM zCnYn4`}u^F*@l;TrN8k;%3|>r$@Vdr=U)3XA$NQfdl3wBlO7+nt>YZsOf;OB#U2LS zX<9$WT-($&X63BNWu6>pW0ngSsSO}{rBnKGsCRzIQG!)Lj)*Tkk#MgOImtX(r z^{cz)=57aUuZSmchA@hBKVor4ve&jSIellC?JTUKpa|~YK=HuI2`YYX*w^F72ZOYM z?Sp{eKor|Cr;IE{AL#$(W2_i4S-4Y4fGpTBD}Zf!_#0n0pFIqQi)9E=?NZ~ieGqh= z=@H9E$?&@xGaS=ynbyw{+HSv(N{sGKmqSwx)L-j;F+#CJsOZCRZt0T5kz>2s^JM#M zir=BG1)$C-!x!fh9OhAseu5t-T)KI;^UU+nsok_Cn%^#DkPTtdyvI?npO`K4!M!8f zAytjsAPpYN!TxQ3Z&ebM@g1&)(=&FzO)OToSDPr}?fQJjIe+X}H^^rVnYEMlmieT; z^NQJLZRp1R?pb8*1<_->gBpo~|7_rG!lWbK*+8HSrjQd^u_C`33{3nObQTVij1fS-aN8U}X2^3(3ErJB(LTDHu+xdD{x*xL&2*yWLGf1X9L&-` zdI#!=w7(~?3lJA3{)G!~@T0-!yJXA4N0QxdV(!DTHMEkmAp;rM+PG9eaWjR8GL(4k z_y1vbeIciF&6;*(4*|W;nsQ_g0lr_Jbd>G?iCq!mKpk?(t`?W?g+60iLLs4!uda?a zqoO9GLXIy{Qc`Gw{F)GP$k_aJ$lGy^HlqVV*R;Jw)ljv7Shc9ti)r`Lk!NggQ!?*G zdbBM@f9FG~>y()Q)rwwPbi!qc6tiEjj=qPxPIe0%7-wHr{cS%^&Xgs$YBPFs0?>$S zL!%eO`)v44HB3jWqqSq$OW6V3vr~9|HfijnfRQlbTH`(@KhVdrOlqRyo#-i!J}dsM zI{9?!dj|JzpXylGI>94L_t}YxvTTZ3MJ!-(c>PrO;(_tWWtE$kmZ0!|wzbeX3A&?u z*-WdyRTs1Gq7plYMuXXaS>fEH-S@l3z86&$o7we{Q|m=Yx^392uEN6qy37X; ziIyWbl{1&MJ2H~*-1}5Sp<%6r%$QD{zFjlOB=*1{qFB!JR|x)vHaM)7e_B|4r4lTV z^Ly;;johK)54-nQe(#UZ9WR}8(EpgdS5oA;(Ucx-F>P?cy6Ja(!M*`CiDsnate+y) zxd=1wOie0Z-1%ob^qB4zv*0kNMx3TBuu)QktaXTMy#X126dIIW8%S_#!RVJ(VE-@p@&a5^D%#6P+-xg+Kls3|_S zDm$3YWu>hSg3#_ku@jR7AuDqq;^oJFPu5mkmN5z+$^P$hTE1u(&icn!=Rj@F$c!)3 z@&y1K?!=OGNyrClT9v=8V>t-p&xOI|bvD zN*Y@C-7rMR!Rx3*=n_WsdMMpSe9-}=>()dla~)$wc+p`%WAx}yM>dLz;G+%1G#K74 z1qV*~kS}b+KRVQ!5GIXDTHq?XfM)_Nu=ZWLRS2tLf?}` z4ftE!V>r=AViB{(l;LwuZR-V$+-{0nxND~;IpVtQPLYA|Cx=ftbz~tDXZV5<3oYf# zAJJ?Ks}kqY489WjrQbH~$3xaP;T9 zZ>Er~KT<22(=iF#}eMnApjTW-CMo&un(WZ z)Gs;T;7dm%c13Zo1(#CN^d3=P|m#-$TE@DE?rc?x=5wlr0VnsXT0($o7rhWJbzbBZN z1I#GL z|K$BS6m$HofSASSV3uQT*5K1|c%gAzFERUlc;5}D{eE3HeY?yuBt`5S>Fu3c|f4z1j8wzbVUK&I6ONLG=4fzkT zFd<_w{*P{32f>lNHO`GaHZ(t2?V80J#9473A@sOUm}S8-#==5~aqv*mls&V;9ZwHf zgOHdr92>Z;_Vf$<-2u%FZV&R+0NxGec{uxSjay+Gc#TiP|Ec=C+0{XFF5gkALVG;3 z7%*pfL3iukt3qlEV118uEhcgt4zh?R{xdf+S*wM_V!Yd);<}Clcmbx@V=bkf+l+Yd z0E9?6b7F|c`l2mN`)b*@7XFiMO9!Qgb|an9%_I2Ta{3_qC(ks*ZQ$OL`k?xU!#u(} zZE(*2RaN=umm4I`l3!1_rNdeJj;fjYkHW=ed6=qMe2!K-A-!#jgl3xeJaYhXDAH;d zGMA|d9-v^E+>^@%#oUvT$?KaPln10LkhdQj037G>%&Pa0_K@4L#`l7^U!3iiQM;C! zwdZUv+7GWMh#bDoNRMszF!#sHgGJ_PTnCbO8oll z;ua7)jv^pI;u2Ufj%jr8&Eyjxyf)+0jyT-jo`D z(1RDHj#XhxhBm@L!J}5M!yxah*J1K)sEy02lqhru46?9VbJ@YR9`zR%pt zU2i0Q*)400+yX565*q|+Zjdi7VeSFW-N9kuiZQ>}2K(N;SNfne&&Xet5s-rtNw(zJ z+Uk(WDafcMPFLX?#$_a;xDR;LpCmds_f;pL=CVAUaBI{v?6^waT~mpE(ulD%&8GMN zxlAQ$;htgnXbbY5G5O|N60IZC@tFt-cgOhX19(jU!OmDyM1sQ9-7#sUccMqz$$!(v zLtYw}GMsMxiw9~>m_>j)xCi5mObCm$161|aAV}d%cOIR!oAHdH1+hJNZUe&ucQuIl zjK?Nf<>nJHKC19cd94SX!HD3c<$dLZKSV$_?4TXc8n}g9vwZ&n%HkfunATpgKKK;b zIOwo>!iMXI;y(PR$CHhc;I+#_jr$Ta&t)^FN--d?b8f6)eVBr;a1;Z8;6`s z=FS|xGxg=eYfQdxS6ae9xp}u3Rdso zc(eRF>`Z{R*(BmMUi#X$IW7GJ2LN)Z9L_0vWcwEMeKW~G1)`UxI8=6DAElKs z-<{^N;*Et5-&Qv<<>;+LUpS{o*7-&>*1uxm(TfG*{BOuQk0e#@1fd$V%!i{IJkDEW z)3earyA&wJy}Vu~e*16Fl6*_(QIA!5y)h%wvKUTsP!b>epI|V3 zRuD$W-BPk4g~4j=q0$W^`B$v(h0?FPEB_fDp}~5V?@V~#iYoOCNAiUt&tY$%#)nCJ zk6U0Z;^iy675JVfhU#wk;aRw+J^c0t`-NhYmFk)5KX9)iDH^pe^Y)3pfKuwRFv1US zB95vrN~z6x!e{PXMb+vM884d8i1S6-7Dd3_r=`nVk72#k-mGekQ}^-|l{txT|JGe~ zpCNB|2zcPl!aEm&z!Sa8`zCfS?7Y9zNcBfzSazie|IKdMH!*NwXZ@WOy7vJs#Wy>rZ~N@hs!0LIVZ_bGud)qzsb2^s z@txammR{q&ub6O;`PVH{=UJvZrD>6XuH5<&ZD~n!6QZ|wV8hNQ>193;sfFVf(^$%R zS)zr0bdn?$`N-!l9~L{$+hI?7^K1EBQs|!~59nk?Rqi7vm6H4lE^&);|9@DU3{-=i znL;gtwfB;|kAu`f&BU;49B?jF+A<%qH~rHO%pT3dKKlV5xzV71&RDSife4215~u&W za1z~8!)jWS0IiU4=qH0~G(d+U4=7EKCB({0@NuIpv0_U9ULr!py^EVGnoG~%u zMwafmojv9f8Bv&aSmLG*q-4oU4 zrl`*<^t~9iJ&xYjJdXB0&%TE1$G^$}?EI(c>hIA9#nptm5YYNrynvgm=U&fequBU-N{& zizDqLXXkN#7bDzf0FGB7V*C^OxMc~Nq`T|c5c|6Lh_L25uN>gz14uV$n}}(%RT>KTa-&IV7V~A9jFVXhtDQk>RajedZq|T zm3wg*(p;$j4WC;|ALMlj7|O%4u_0Ds*xu*>6X{Rv)Ol&uE&*U;Rtki3`Un|VA=Gsh zm^e5OypBQ`3WPKIfPc{{!HHuy|7Q@tXP}le4=IVpPJUa!A+9DJF@&u0Uz+E90sXK- znCp%(aqu2w9a}IINN0Qz{bE9xn~vCV!5(BiTkj~4&i{KW?`*?}2&tRT1F_wGYtt%= zu@`LbP=UB-{Ws3mVqTgZlzN3{?(ybwIu9`Z#PMl`2CM%AF~P3egKLh}=!C-#D!o$p zgz9=~j(>~pCZfJxHkL3)_Gpl?9{QFE5#j&TQVW*jZu%eK`({Fv90SYGrhgY|VRGh8 z{{m>kHWOmye)E%L>RWb%3h0$|!;&LK-~14mE|*yOcj%M5x=zoiXv+MbibLgMOxJ&c zBDxWPZ+OHZWumeshfXJ#DylfL>sWY=w-Ye?kgDC-TvK|4nA&ANPVNFJkcf4x}IGJ=Do;J=lk#$1w)^idKjWKo;Sc;N+n zc)j`buZsr$JBxenR_8)Aw1uQnt>tUFtr{ScZL!qS-mr1bwx*z}a(6v{?3 zu>bo15G>S$DV0Jyp4U_jCB0CUp{`H*OhwOc`bFAXYXw8guJq|Se|-CZ2!2&#DN5|amfqffn0A~uKo zd$$lM@-HJ%b!JcTARj@uFOHF3tW(US%N{YcgjeoHH6Jd}~z ztZB!PaSYEkITy|SaScxcEb#|B*0yLRyDIbT8JMZ=^!-$O0P7t@DE7g8z$=1xMcj{h zpc?s?WY85JwYq6sX)UgG2(5N8vZtP70Pdv610@w>GUE=h`Rn9F>Gz806nwi%wUwKJ z;8Uak{;ns|STys2R^&9?uiiYsxD`)=t_!U8a<@v{BZ;57%*Gx%qeomOv4E>M%v@jDASu6UYd^K*_nL;(; z{{oJBKffmZlKzNM#FaFu{LA37?(|z}Ipq+RGQ%fKzi{y-HZixc zI-aVjXN_2zv1^8?<-+-$+9+L?cT2&tzb@%ldRt{F!AT>~pXe!bg^NpOFACesr9)a^ zX|Uqz+m|_Q^P#bw%poRzrSrjd(igwT5)os?`)Kt|=i9H(AVZ-@%KqD4wswao4WLzZ z5P=eBiZo|R-HJqPDIpmgaBQ1jHJy{(`VCXFGZ!>`831Tay>3diNBW%@Wt{Qg9rh4N#k2t3F_B zs}Hbn3{-#4c_*m&jht>E8rMvkKV3ypBPkKzVjzmste2RBN?N*SAcBZkMUl2=AcQF0 z0d7xmeVJH~6Y$IsFYkYR>BHFG7`*nxSnY@IS%abXb;LMB-qaJI(~)V9erx6A7Noz6Pq(c;mcRUoCX$iBTLU z_8O#-wcn?1SGnJC_HTl_8P_N7e>xiRZ}y>S1t(N%M*hYqS?ZWCmE1tYOQB~X_D(MO z7CMPT!;{y8m^9yUTPk@%J8dWaij?Sf**-&>U%dHVxYp+Rk1sgx&@s?Mi3i@$7J4aMSrB~w|0)vQ}# zR?BrrKM%lke;6MSe(xjk4!dHZeJ=XoZsB=U+ah~dr(JaQNN{awb!_!vVeG;a(D{8T zT47+6Aad78tcmvF_m-hDs8=fzP6K?S+3#LoO{=Gh8!9@Z7Q)Z{@jH9R-8*!`eA;lq zu57zBf3HVpnoT$cfZm&$LLC;r^J=_ZlSfP=4Qka{1(T?a{0A_?PJ54W>I3nGD~Tk-g)b zh>UR;qsMV$DN<}St{-JosppG`KQ<+5E-rODW6el|bz=FVSt(C?V=kS+Y6@RBCuKif zmlCdp0A`=IvB_p)ti_h<#@FV}<(^{SXZfbZ(ObY+ds?<_xL#@#p8%I5aabtL<`J}} zTU_6buL9NkB%#%9V8v~~zWgaZIdETW}5Hho$4()Al&)*m$O+@q>uv#R+c>F@`quC zk>~f1To35a``|r&-F0xN2x}LpqW$zyVQy{mG*{mn$=|V@0Hjh}?!_b(yr=2G6PJ97 z|IX{;bkOaDe__TrKifN&Nnqkscz z1q*n=elq6ptUJ=PwUJ>NK<`*jfBx_l;8&kCwuX(uvv}@4zmU4PFg9QBe6rZMvrO)G zEa!Ht(_FJ^_gJgnG{9n0btGbMp%0*g)SKGXnyyxv@+{KaEYM)Mb%I)68e3i%TVBjp z4Igt+EzWLfCfXx3m8!PgIc6vSfNQ2XO}d;bgyS@Kz;nyq!c2t1sl$4#AZ=Z<3XAOy z<}%y()|}UP+YYFD#Blr-x&!JhnA6TCw4aUO1!}daw2W4_=#Pv>F7TgkyUvagpaDP# zwc6m+WJ5-4iUpw6bu-n;O*bdU{A+wAJ|^~d2DO5v5OuBnMU4IJszr0F{*G^*DFFY| zR#HbaJB(qetDS;-r`Mb|4Qf2P3|*{*8>vf~N&|qg`AnsGx!SuY8$XdurN#j|{<{zT z_PX0iWQMjI#g!Ms#E(vh?OC0Ky0?oYZ4F_ScXh z?0KYx)aeZ1nmPXW;7FS}U~Q8$^R5qZqDhR)4m*bQb^z(_b1J*&YDLy!g`3S>a4j%sEzxA1 zoB>&Ss+7Hp!k4UWq1RxHnu#*>4 zQBaB6exz)Dfr=Q{5J(zBV~;t$=!={m8=2oLd!sF|p z6$9X3DQ&5iMJn&Yj)I$KqW#GI;<}`*Is98^*49FwxwN6yQV^u0HQiM}Fl%E0aht8H`Vq=qUq(M$ z!#ttlwU}R=?4?s#eC4%hh6&=f&R!L`(kN~eXgwL%&0amcY>=>b-8IPs&;OVse@%1T z_dQ#4=8imDU!5CrueJP}D=)*!8-Z5BqwXu~keSV$>#ClT)P1mOoPx>11=T6)+eR%) zA>F8^k4moB)5_(-FX0E&y@ugT5WQMKg;TE7(Wv^B)kz_Z%a(eGcII^|usxV$bgIr4 z;1TBt7?BJ?&EN{2@tMWcc)tA|PV+Tp|3 zw#c4TE{1p%R-zdM=?meDCWuf4Ph2U)w7Si}_PL>Y1A(WdGmLlsEDZek@cY4m?7Z#X zJ75oK5fn^T?EP#!7sc(K&fc#gdhJ^EGgu*Wp$@!9n&mdzSXG*>e{yVTAtOk-c(sxb z#q@RGcdzy1J#w#o<~g#jZCkvW%8!Fgd@5&UyB8(C(}jX+_%DQXl?3HfxK-~{sd%r; zc4P}FH696t{Xrtqk0}O(`>ufogpbYf#Y9$!9u-99i2MZ9eJ*3qradJL<`X9_9d`Au zL%$7(Dh}`F$mK2{%O~53gkx4ph40GLOVtUPEMDXQR;LeCpV>LLA=55E{gGzUky)2o z?iCM%$wOwHOjCTIRpSo8;Wu%X9Ssn&=^{vFFSA{4S$^JXrnw#CSkGR;)AzcSDFsni zF_^iyG37;Kdq8(br&RC3KHfBd2QloR?>WJ-vSFycXy36(+n(zvrpTV!ErP1K8(6k# zvP-Jn6587fb!bRCk*-}C7-D8xHc26cI2CH!aSg`+z!OZo85`2Vw(Q+8fX0bqo{Sag z+9gZP6KvO;0l${;@DpTKshyg23Rx@nq&(?Wm)Q*))BlIIw*ZRk>E48skYEWA+&#Fv zLvWYDo!}PSJ-E9&48h$Uf(LhZw}HV1mv7$RyYKFQt9G~c`>MXGr_X)*^u1j*(=|P( zPv1U={f|~f$g+5D|BW=gitBKa9;>Owq+3uW`=~mvZ)(&c?QG+SvmUD+c4wDtlXc;= z+cYMNe3z{2X~KG&Ni$=c7xsFmtl4S8a@$dirkQo2fKhspY|(LoUK^0M)tgI}D52e$ zr@iEq^N6DtQHqfj z4ODQx#LN4!>p-(tU`3SPpRHhBH>9&hRQ?g9yGX)xmmyr%A=G+aj2EAu6@fI=oW{<{ ze|DJ_S#MC{VwjWr%rV=WBc#mApei?3B&3YNfFb@_d|E`lLCkXDS$}dB(jptX3Te`@ z10S7bA8ER6a@gT7w72c1m_RUYMv{N4->g= zy5B83kMCdAbhi0pyDK+nC)vGxKA?%WsIw`wZE-gXRFrZT5^() zn-whoWY3H?tDpYKnK3R=pKig4K5mx3OwXPfY*s%-0O6WY8*CZD(ZDrsXE}(f?ZLs1 zs`Xc9@YD;uWLHYAR5dNHtpL(T5-t6pM;e62g>1r;40K?}8KO1TH2s1!IQ8QTQsJAp z$Il%;Xau9Vqlk;|H$Knr7K0>#4%<~0{8d9A*M2n`S~Vb_){e8a_hnBLfd&LYC~hg) zUr$C9`lY#XiTgt@481=VZ>eU5#O^qIe=*|O#e1}_sB3${t^h+ocU@|qtZ8+S`KbPYwL2lycCRS`F?2)=?Pk|dKiId> zJ-`!*S6&ZjelV7IB@g1GL;ixIdV{P&R{}z$Z4Vf!Itmqaz{%*-!?ej+4yfF&nhWQK zA@7ALjlW0rjbho3pKD|Wm-30|l`+!Gl)BFZ_5yD%xk>pm1yPH)3nqlZBm3rVC|c;( z(sKfEEnHt27ye`v>hzKyt2eYS9($X&)YtLPsZqv>eNxWDpraWWp*2y8rnj?rxoRL4Iemd=*bSdxWoJWakrO#gFljM za%a5W{kmeWx_4)fp#`&f+jY&K&jI^(TlR_QF^q&@%W<>wZR)NQ^N0`gu_ z{zKB7>#vg@VTWsfoNT3V?MB=^rYc5=u@5QR=;p-Tc8S&^pX`Oqb{xif(cRJf2Knwk zTh-#oDuqIAdl*N}5dMXb;(?%lqq*Shs2>?5hV2^Ky3?=gU{uA;qLG!BxrT9)z+f?8 z)*$SX5H%fBdGv>~L^C0qx@$4|>%oehV(~ygLuYQ&;_R*GilAaH@rHt5-=&ByC|%ZG zD=qUi|9ToH@bm&*H#XCr4bP1FG2ofY5T|(!$xq(%lOMfDl@bJD&V}%EdL8^ zyw1*U%o_67+q0`OQJ!pVmqQCooRw7lF=k4{FeAD*^rC-WQc*g*gO&6tsJ9o#nH(Cr zzP$AI{z6PVF%)`z2^}N3A)!M;_aL`4-&nKTMZ& zYXLf!-p(dB9~MF!)Sa_13C+d9jllYfBYHaC(TIsUU_Ee$NeYaNUUBlVoVTY;p{5Ld zgy_rYNYOUwGakw=Du2Z07R%TlI~Md^_ctgWgXQp~1uZeSKk9#71H`!u38h4$?UC%|0}jghSKYli@7+ zf&gr_ZzlzU;jm?H>1Ey?NzxTa^=PLS@sMeRaHJUg$Zn*)7M_!A0z$$hfS;*-)C2=oJJMLNay>Yc_xp=9Q-)+i3279=%s6ygP6A2UtBn!HXM*hwX`4FKF zMiTE1#9r6v-UGe~)T7t;^m#w*@=W*$|* zH!qH^pQZdQDc(7wVT?w(%P8mYVmKsOKz>#PjkD!#d;8q32_tBJxMuw?jMX`r6*h~h z9pjwkfSq&SmW9!0^Z?Z(f`(fA|NKTVLi2@?hfsf5Q|QnwYY#7syyu1;G9roTyK8Xy z)D?>`VfUxMrlO3VepDBuYFIZ4!BEVM43rt=lUQrVdMiKJHN3=?zG}~R{wJGxV{E+z z?rukLEtV!N0`7tYI=XU0)rP*Tv0H#=*jPh}xpL2cPqE?5&GQFMkHt0JBqzVcwWYFry=KBf142)4YKhXRJgzp&8jpgAj&oC{Si`UbCQp$UWi1FS31GUn- zPl$Qn-(yh!`taYB!h3w0dwgkV7KIn}d$^j}XKl7S7c?C9SH|4%|Y7Ohe;e4zjsZ3T5A2-9&E zAnAN9Ak>-mw=sZ-)Dvxk;<_I5^T0{RvD931uei9_%wL8RJnsASgS}sQw2`k!B{-QS=$mG^ceI z5?JGZfw)@i}RE>YAnuu_+k`hHj85$z%{ZxbtsX7gYD&nW~XPNZp5kyY48fgh)+5&Sm zq~HkKL(=|IcvEUgvXPM+ElhD?aexv4Llxswx)9y9xf<4|WN}iLAakK##(I1c4)blK(qs9M~yhiu$ML zIB=p_3~@MEqB2?{poqXJ%NbWeNVMxa8`~?v3M35I_1(w%VIH@c7(q~`G35^;><+e?z zv!d|G)J6M`4Ln{`W~vbfRTU)!P|K-|AYv6cVWoMss!AbN@>a zk(xHBD!t?TYMhYmdk2fcDMt+L7?Dvmg{uj|DxvdbEknb7bU~qTLQ(@v zaUYr%-Q-#|LV^PgLNrrW0~Bkv%|BcY0Pfs6KA~%yTtBoGR$~?-KNZhJpDt7`Nv#Mb z*-KNJF8YDg!uvW5gOr_7W$*v5$~R(6gIh4hCh7FqcA{yj_+hdhkxwV6eOhtkmEzHR z`3|UF*3222Jq?&XTdx*Z3@)5LH7s2an!mQLF}HXzsm!f_D5fHP=G$L@cml>tM;N~Z zLL8g)2fty3dwdm>+$Rs1tWC6X@jf9 zlfwrLC4e#Vv=99=7oB3F?t<~x3s+OrbX7o=Ttq*k)m;7uhE}KA;$nACZzD^$=3-*V z4fg)Dd51$b7ZLqS)2^f@pD^d!FVM@t)wRi$p`qqOEKuwr(fP`H+hAn#i^`~mBr)A4 zDfwNvCxsxIZ>A=Wsp)YnP7fGzQ{>4WuUWRBi}gw(t6|Z(8s^9fxzCZyJ}Q+)muO;{ zhVDXE*&*wUyzKp2Owp1VJ8dj6Y@vMogrT)^^f zXiM`;zXMLt?&W+<8R&yIlEDxc^LwrzWR!-iz7e_G|LNZ?B-zw$+jcF`%YpcOD5<9I zIf=RY+4)P)r|s4&gAkF2Y7zfb0}Hj4`(;5v&Pkbu%i8LTTA%Rj^-MH9*Z!(F1x(mq zhK2{Vb#@oz`S*Ipm<4&)L4a}#R<7Sp#Q5s}WZ}BQP6n$DA6|aI`az1dE#487dWrbY z3Q@MN!{lFUjeSjjes$n433fxZG>uv={#=<~Z$-4d0jhRGfe!Qvy`}dS7IHpomkTwt zE<#1TToZG4KAbs8m%pQ^O!-S&tH%3g(_+mpJ5HH?yvGVSqiHIB1zq#qM^66hUs5v$ z)6leRYeV9v1YDCLA8##;o}t>~yPIBrZuroU+w-adEs zx#C<$5aKm$EJ``8B64&xu`B-obOAANXcwHEyy^6Y=uO=1>{E7%vL!6nr?P~vt}bq< zHZL4=tC8%ZHcu=WG&puALdr%!enGAqJYBQNcI!3hJGlhLeG)M4Hn;6NYk_eK=uB^S zKsg`qX(3i&#{8!z(X<$YJ{-3H*p+D-FN*m}FaKqoi9?)I-t~_OZv?fGi|=uLWAGi& zZ3meyWS%=~2SBagb!(8;0Z3qg6V@&6CX-JNRt&%Qs`SFz^GaHpq1vMz#I7|5O=dzLZ*?Nm+x?{b;285kD8<-o(<5zV{4gCp6 z)DLx9uTCm6zb#MlEKiaw ztr9G)!l2NMo+{!Dn}2U}@~i1aIzLXZ^~Nj9roj&|ihTt7V5658{F&X}|26t}GwuIY z=-U)%tRBs$N!XMV6r4#53h6)3H+-GVWa(U1pC9sVqn0aVDV|9}VmB3a69i0qpB)e0f;?Oj15b{DSl{iH=hHpQ(Ty( z+oqY^R5@|V@#-s$_%!{#s`Kop^raik+vesB13nhg!=0aEszC7yVeZ^%>V6+n-F7Ek z@kokZm9Kh}E{RT4if@6t(`7ZF%`>Q8F}X_xbhx~`r1Y%w5g&-+vC}t^A|@JD6YC|3 zXML%$$%xn(K0W>8wmXAAQ=iUlpTQjLu5AlMSk10<JXhbl$>nZmKDGdh+Fp2`G z{|5yq04Nes0DdR{FBE_s3eC$)B;HArieh<`k?0Nuoz}B8Wp$8{a&u<1PXmvKzg{H2 zX~UpCI)t%2GKQf%R)K{rH9d5ag7J2aVwxg+RHmE7P1;Dzy%4(7A8y^3(f=}y8%{Gl z1VPt1-lb0G8D=Y(O$aPd8C#&3j^E%`7An>mpPrufTu}yf&#A~yZgP0AUE0_goIH#Y zcAs)*gw6*ivpeGZbhPgYjTXq*Q2qZi5sa6WQrnLb{ArT9+@*1b5 zEk%nVux;(*Wp`)}r?O}J6s4&&TS&W7FrcgZU@zYb+H*j!E%v z*-D1b*?{iu)9Y2Eg?${$p9M6R6#0QJXM?EMEuuG_eL8kW&D!1Vud}}8koKbcX03(= zoo-C+wfq5223M$rr32jjF@#T~7)nNJ;BeJSTV z6&_C2dbOO7BLDI&W}1V0^g(^T)7v7+qvG31{mtT$vIXF8jBd|WyHbsl^PpBv{*;y+ zgEeBG03q+0sKsLkdrO;?kmJG)N5fWuMaks);vq=|Su4Kf=&ytZ(|nI2k4Cxyqrlx+ z6=s<6iOm7L8n*Rw?c!a9CQQG#+H6zkb`sa90_*uYJ>PK46TTaZkt&|upe7fkx)@wa zhiyKWK4g&B?&j{_f{NdVB$F$N-_CMr^jvR4SHqJ|9R3u(WyMTe~tm{1Ja2|{^Nz!eED2?H~?z#&#)OMkKo?gf%Z8l` zN~bxrSLL#Sr&>Fvr`tL^yUC--O`7V35v$51>-}$>L?y|LmCn|M_p;Z?+V0KwcVSD- zsXkuI|3z>;Dmjba>>oYdzaJDAE%?VXB+9ND+j(;@%u?R_#el?2Ep7jEf5p)F&8(Rx zs*q1&u5azV#wxmENPE;VA+FJs*TP>NacfQhy17K)!_n5>GHI?iH(rMK$5;tbI^?J> z-D%L$LCYtdg8Wi+2UrO)1BK}R*b8HfvvQO938HQq@MY%Jj5elu4aHA-AAFY3bvCb@ zlhtcg1J|J({>mF9FTE+@oRlMFgpHi=)iEqR3YP9as_gBjxK1}Ne0}tW7|mwsWOoP4~7dou3D?#hMHQ9 zotvm7UD-Alr<78(3-E~P;!Sr7Gp(1+DWo(~xbmIPp9MM;imC1R*@`YV0fb{0o&h@jiEof3N&MeKW;&Z;`n!(i} z&-Uq6K6Ee85)krqf9XrKC{GnslgnV;;99YO*Vx3Sh3QxbP}4d5>6|Cisy6zx%-)_R zF4~IaR%@&VX(Id{X>5XXcQCxUyvB`exW!;XBFe z@g$^`J5yiiatZRQBO1IH(uKRc>E?a|j=f!V;P3h|Zx-^so%2h=eR~p98x~!1vq+M@ zU0m7T;0Z9h|1~Mu=9c6&)WS9O;Bb!Q2zGxUNe7jO_N@!7Tyk3{$lp2?g-G4b`uPbE zR23WPNVfSVoxJrSIzE?_FOGbjwsFtNmn%sp0p)(Rq@@6sW}5)E{`=fgepA zYU7&fyxU;p+7RRp0z*u%^Htw7NXQ9wT^Bi;D7>c?$r~$<+K`&kh4+5u=^{Ld+Pn}#VUKNb7 zo-b}by;afUn?m=&>#y-82i+(58@v=UZ<4Ru=MK|7Z#sg&Mie}V->hPXkBIZs+nh#& zqnU%)8{exD#jCFN&|Au6lB4Lj-@Kg+;3cSk;v6gf#u4=p9&pytpL6aCIJ*w_S+4|6 zVggsDfh$`k;%<>)o~;(nK_#yGb!F{(s!z{v`R9CF<P-nWl2pS1OXW*}y zkA>7rm_A4Kf$-`-OHfczX+F@3Cl&n)`1OHys}C6w5lgA|T?9sajPu9ecMpE%=kjuL zBn`#gZ|CMz_4Vc>>jKx=;PhpIOSG7uA6VBBROygZ%fW?&%Yl5#gl@kP&!sS#2oG_K z@Xn>kwAIkv3dzo8K2?94krl3DHyPQYj=Xk^qeE#$j4Ow4m6^(br{_Y-JoPqwtDa0v zLTt)}Ez%*X*deeF*81TkeeU;J-n3a6W+8*ouz9*32`JL#ho2+a6VEi8Ym zT_(*n6)n|?t6N37F8XqW=$S(~CCZ*$v8qdv3L(9{3v}9Q$`yaLdUZgy27~<9t{8 zAc>7op`n$FS8sT)UnsjwwYT2%eyJ{7;A<@q%`1n&-;k>TZzQikyS>ciCvW`C3Ce3i zZ>Fa(@FCo?v+c*)$xqk;J~T=2%k=Tzl$Y+v2;__A`ySqmV7I# zp#Wx-Or(U@_iOzOE}^liO$Nr4jH*XI0^jS<;e}r>c}{Dxo8b?9+WF8Vt^1A9D04s! zh`UNwh0axL18i*xJVQeXYXXH?P!a8Z_BX&8m!jKHu+%k2Oz{qKKKh0z!x zF76m#QlJbF)P@yD&Kt2Y(cQxLm3wrh{yp`y)HmH&vfks^S@b&V)PIJpuD&Dfo_zY7 zIT7kE&?Q1aPL^Tl;P(v zx%lAL_~W|YU+bbO7=TwlJ({RVPlsj2rI+ROnI;k#Oi=(Df)u%^&3^^2w5DZlQ(p$o z9Pc^;9|~)7%p#y7NUw zjU}-Ev-LYa1NQKMQJgMWY8dvOW2;C9_2Q_!QOUC?5n3N64daHAOfnX_s<@iunCfAf zgi)7O1zzO9iHJ+-y|`ZfD@97V^&E#$ben=6m9Gj{34Xu!ylx}f=^WvSLaq3E`8lS} z{7YHEQW0-y)lQA4vddkIrv&7Re_li2RC?Y3>G}ht&U0B7Kt2c0q!z7O(81239u0{o z3Af77Q1vM_^GcqNwaRx(c~m>Qm{4z@dk>~{k-`PHPL8)rI@=;@xznxGg~IsJd9X+v~WxxVp!U2(Osz*XIaTNL6>|pKXzCZ&zU5 zKH7A^1%?K^xyOFY4p7h!&6AxP@S=BTJ=%8p;`zy^gDSv0&{uyk&u?neixmgs%T*hk zXu!69>{j%ae6<@hOWF|xiSkoohj}1jk3zLU4d2q405RzEt;Y-bJ3+he{gLh)d0`P^ zojuTqhbKtUCSt4|Eb&J12^&jN$5NKy@uSA+gN=KOQwwYG`cd{YU*{e0P7Dm$h}|IW z+F;(4^cF$5P_gj&FXcP)x7sO+p7oEkE@7*^;WQ@F?xn zpCEm#z}4ehR%y2>Leq%z-+aTpZS}s|Sks-5>$(P_Jh;Cyo^igy>Ie+Lz8(Y5i)y1)))$8<9@Ura9Rg z#AWU3nbrMu&*BX#z9X2&I8a4w(6{zr{=GWMqhRIRFM-TSlR?9VsLM=pD6{)p%xv_G z2Jo^W`}xE${~Le`X0U|Z8cau>-H)-ovN`#G4~AhA7KtD7>Hx0{P@T>TnG zMl;%=y(^ECXb3BBj`VWIk4!aCpI=4?B zY(MoVP{=sf9`4fU0B%vV+R|0%c4*o!M%}hH-mF{$z*MBA$T=deXJ++YBANBSulF{M zIDxS?<88aHW^*rk87f72u0#7Nd%RDIRrPi;)n9&cWP9t*j*;rKzOqx5xpx-E2=9syUxBdC5UtiRs4l-X8AcPvMl zIpszp2bMjM55iFX{7n=~Rk7};8kk+!I)8D$0dSQ27Ed#g`h7f_WsKS5d=a?jL}1%5 zd3Y-e7F<%n|1E^w{Tls%clWk>uciMi7)QQ=-O6@ETPJt)?7mWbV4QTZS+MY?^Li|K z(N8a!VLjG8mR+Q!>#3UaEbz-{cg$~`|Jo_WM1i4{3L*;fII-(a&u`9aO|(E<+GfvC zXk4oh(R)n5QWkg&UQkxip2S)2*REf(Im8aU64Rm({z3vHE!w$l9`EUBfR zUvaLeX*|{xUvlQtbkTGQ;rJ}JRgWe7RcyJ^9~o`gMmV1&c^wx6IiikJ*i0#F9XsiZ zOnsAZYu*PhZf+*-T!9beXN;lb#UR~9>6{V;1)H1v*meOZI{7GqyEF+`6| zk8bSoB9k1JFgq2{nPudI1f`1=(H?IQJlBh-%1UO-s2i*}XSxe>Y5cK%98T2*|CsNd zQm!dCZNT&SiR4`MrLtIPYS--tlPsSlQ*wdN(&(%&uN>wPJbPW->|Znm^59viGj?TB za^gIb4J^;nZ2h9|OsN3Wt}Lcv)vkbQAkdq`K>pYp>87z|cF{<|U^cr8%k?qi7@E-# z-qp4k;5}*ZwP1Q#m+vt0nsbd+1V%hJ- zsi@Z}Ue@7WryY=Qok$z%G8auA?IpjPS64-)H}t_@ldq6PpXj*Hn06bwgJxgR6rN}Q<^Y1ByLUK}m<=lRBbWzWa-w=24_tv=SoPr3L9jcJb>Oh1$edg<1 zRtzALBkwrgwZfM9$Kh6lkeHU>MWlRD>5B_^l?JQ|0Vbq4&{`!*0aC;TgLzrCR`lPf z%EF~QWaULRn&($rP{1W9_U3}B#0A+Z^Qvo!mR5M$kiv}M1>Zumf-z!Db`=JtDd|Qj z24TzYGE7zNN>yunMPC(srA3Lx@R71{tIy|qU@N+0jnz5MxfZ>%@0o6;dU0!&uDd5h zjc~_a^ZE@Yxht_(C?zn|4|%*{2`HtaNoC08eI+kpya62&xKD3tFu5|C?85N>YmmaS z9|zaCO=Y$WU|i7`eXUOu!AqOLHB7bOl4<%Y^5Jh?oO3TQXaIxqIiV&nfng-BhFTQ& zdpbu_ncr+TAVa@=QMqLC*hN*Wdhyi3C2-^Wv1h@C)BuF?g>Od(qW;%zc9o=F&n|RK zp%eX5&y&maM8FfpqOWm4DANhhFYMZ$faz6DM&<@ znc%)4=JyG_UrM>{88B%q4N*rLjwHl?*`~us1`m*`u+ocL8XniMkI*nwUc;69z=}ZfMjuxyJPSU=F|8GWW=ql4 z_Bi?pWh8zjxREtbr*A2-?kKTN8yewl_BJb#h6d6g!>K$N`lclie4zZS=$`Ze^!aOS z1T`kwxVRH7qjn3|GW~6`{gQ^v8m+CkC*7TE=0Fb`GMsGq>HwiCJwDuG;=2#$z;{b- zVL)UEE8z)dZGF>GuDmMx&Bo`sPu~azKbOt&+|a5BY!ezcI$(5AN@bAjvvw+B{sBmG&hLee0G&HX!aFutnO zDmF>d-+9JRH;+gomfVhN9^pz$Y7yxYXAq(!fZF`8`_Pe(fn~WTp}Lc$hw(-LCi{}& z-4ZS-B$2j(u0MtbMWO=RN|P$p?;v6X5Q*~Xuq;b~=Z8;{NloEgMzN#26!e#0hQ- z`9Pyl#+#%+vg~n+VX&CdSQ;W+qXZS=kI<*7zPg6H<_B4D{ZJ8U@M_>w&WRC}M-5fs zH&p7C?I+y%eZ1+WmBk3bMAnC~d z+rYLI-q&xR93n|d4X10UP3T>J2UGN-Niks##jsNM7)eI-#h8Q=1{1jce#fUToL

  • YNJcs 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 folder. + * - arm_cortexM7lfdp_math.lib (Cortex-M7, Little endian, Double Precision Floating Point Unit) + * - arm_cortexM7bfdp_math.lib (Cortex-M7, Big endian, Double Precision Floating Point Unit) + * - arm_cortexM7lfsp_math.lib (Cortex-M7, Little endian, Single Precision Floating Point Unit) + * - arm_cortexM7bfsp_math.lib (Cortex-M7, Big endian and Single Precision Floating Point Unit on) + * - arm_cortexM7l_math.lib (Cortex-M7, Little endian) + * - arm_cortexM7b_math.lib (Cortex-M7, Big endian) + * - arm_cortexM4lf_math.lib (Cortex-M4, Little endian, Floating Point Unit) + * - arm_cortexM4bf_math.lib (Cortex-M4, Big endian, Floating Point Unit) + * - arm_cortexM4l_math.lib (Cortex-M4, Little endian) + * - arm_cortexM4b_math.lib (Cortex-M4, Big endian) + * - arm_cortexM3l_math.lib (Cortex-M3, Little endian) + * - arm_cortexM3b_math.lib (Cortex-M3, Big endian) + * - arm_cortexM0l_math.lib (Cortex-M0 / Cortex-M0+, Little endian) + * - arm_cortexM0b_math.lib (Cortex-M0 / Cortex-M0+, Big endian) + * - arm_ARMv8MBLl_math.lib (Armv8-M Baseline, Little endian) + * - arm_ARMv8MMLl_math.lib (Armv8-M Mainline, Little endian) + * - arm_ARMv8MMLlfsp_math.lib (Armv8-M Mainline, Little endian, Single Precision Floating Point Unit) + * - arm_ARMv8MMLld_math.lib (Armv8-M Mainline, Little endian, DSP instructions) + * - arm_ARMv8MMLldfsp_math.lib (Armv8-M Mainline, Little endian, DSP instructions, Single Precision Floating Point Unit) + * + * The library functions are declared in the public file arm_math.h which is placed in the Include folder. + * Simply include this file and link the appropriate library in the application and begin calling the library functions. The Library supports single + * public header file arm_math.h for Cortex-M cores with little endian and big endian. Same header file will be used for floating point unit(FPU) variants. + * Define the appropriate preprocessor macro ARM_MATH_CM7 or ARM_MATH_CM4 or ARM_MATH_CM3 or + * ARM_MATH_CM0 or ARM_MATH_CM0PLUS depending on the target processor in the application. + * For Armv8-M cores define preprocessor macro ARM_MATH_ARMV8MBL or ARM_MATH_ARMV8MML. + * Set preprocessor macro __DSP_PRESENT if Armv8-M Mainline core supports DSP instructions. + * + * + * Examples + * -------- + * + * The library ships with a number of examples which demonstrate how to use the library functions. + * + * Toolchain Support + * ------------ + * + * The library has been developed and tested with MDK version 5.14.0.0 + * The library is being tested in GCC and IAR toolchains and updates on this activity will be made available shortly. + * + * Building the Library + * ------------ + * + * The library installer contains a project file to rebuild libraries on MDK toolchain in the CMSIS\\DSP_Lib\\Source\\ARM folder. + * - arm_cortexM_math.uvprojx + * + * + * The libraries can be built by opening the arm_cortexM_math.uvprojx project in MDK-ARM, selecting a specific target, and defining the optional preprocessor macros detailed above. + * + * Preprocessor Macros + * ------------ + * + * Each library project have different preprocessor macros. + * + * - UNALIGNED_SUPPORT_DISABLE: + * + * Define macro UNALIGNED_SUPPORT_DISABLE, If the silicon does not support unaligned memory access + * + * - ARM_MATH_BIG_ENDIAN: + * + * Define macro ARM_MATH_BIG_ENDIAN to build the library for big endian targets. By default library builds for little endian targets. + * + * - ARM_MATH_MATRIX_CHECK: + * + * Define macro ARM_MATH_MATRIX_CHECK for checking on the input and output sizes of matrices + * + * - ARM_MATH_ROUNDING: + * + * Define macro ARM_MATH_ROUNDING for rounding on support functions + * + * - ARM_MATH_CMx: + * + * Define macro ARM_MATH_CM4 for building the library on Cortex-M4 target, ARM_MATH_CM3 for building library on Cortex-M3 target + * and ARM_MATH_CM0 for building library on Cortex-M0 target, ARM_MATH_CM0PLUS for building library on Cortex-M0+ target, and + * ARM_MATH_CM7 for building the library on cortex-M7. + * + * - ARM_MATH_ARMV8MxL: + * + * Define macro ARM_MATH_ARMV8MBL for building the library on Armv8-M Baseline target, ARM_MATH_ARMV8MML for building library + * on Armv8-M Mainline target. + * + * - __FPU_PRESENT: + * + * Initialize macro __FPU_PRESENT = 1 when building on FPU supported Targets. Enable this macro for floating point libraries. + * + * - __DSP_PRESENT: + * + * Initialize macro __DSP_PRESENT = 1 when Armv8-M Mainline core supports DSP instructions. + * + *
    + * CMSIS-DSP in ARM::CMSIS Pack + * ----------------------------- + * + * The following files relevant to CMSIS-DSP are present in the ARM::CMSIS Pack directories: + * |File/Folder |Content | + * |------------------------------|------------------------------------------------------------------------| + * |\b CMSIS\\Documentation\\DSP | This documentation | + * |\b CMSIS\\DSP_Lib | Software license agreement (license.txt) | + * |\b CMSIS\\DSP_Lib\\Examples | Example projects demonstrating the usage of the library functions | + * |\b CMSIS\\DSP_Lib\\Source | Source files for rebuilding the library | + * + *
    + * Revision History of CMSIS-DSP + * ------------ + * Please refer to \ref ChangeLog_pg. + * + * Copyright Notice + * ------------ + * + * Copyright (C) 2010-2015 Arm Limited. All rights reserved. + */ + + +/** + * @defgroup groupMath Basic Math Functions + */ + +/** + * @defgroup groupFastMath Fast Math Functions + * This set of functions provides a fast approximation to sine, cosine, and square root. + * As compared to most of the other functions in the CMSIS math library, the fast math functions + * operate on individual values and not arrays. + * There are separate functions for Q15, Q31, and floating-point data. + * + */ + +/** + * @defgroup groupCmplxMath Complex Math Functions + * This set of functions operates on complex data vectors. + * The data in the complex arrays is stored in an interleaved fashion + * (real, imag, real, imag, ...). + * In the API functions, the number of samples in a complex array refers + * to the number of complex values; the array contains twice this number of + * real values. + */ + +/** + * @defgroup groupFilters Filtering Functions + */ + +/** + * @defgroup groupMatrix Matrix Functions + * + * This set of functions provides basic matrix math operations. + * The functions operate on matrix data structures. For example, + * the type + * definition for the floating-point matrix structure is shown + * below: + *
    + *     typedef struct
    + *     {
    + *       uint16_t numRows;     // number of rows of the matrix.
    + *       uint16_t numCols;     // number of columns of the matrix.
    + *       float32_t *pData;     // points to the data of the matrix.
    + *     } arm_matrix_instance_f32;
    + * 
    + * There are similar definitions for Q15 and Q31 data types. + * + * The structure specifies the size of the matrix and then points to + * an array of data. The array is of size numRows X numCols + * and the values are arranged in row order. That is, the + * matrix element (i, j) is stored at: + *
    + *     pData[i*numCols + j]
    + * 
    + * + * \par Init Functions + * There is an associated initialization function for each type of matrix + * data structure. + * The initialization function sets the values of the internal structure fields. + * Refer to the function arm_mat_init_f32(), arm_mat_init_q31() + * and arm_mat_init_q15() for floating-point, Q31 and Q15 types, respectively. + * + * \par + * Use of the initialization function is optional. However, if initialization function is used + * then the instance structure cannot be placed into a const data section. + * To place the instance structure in a const data + * section, manually initialize the data structure. For example: + *
    + * arm_matrix_instance_f32 S = {nRows, nColumns, pData};
    + * arm_matrix_instance_q31 S = {nRows, nColumns, pData};
    + * arm_matrix_instance_q15 S = {nRows, nColumns, pData};
    + * 
    + * where nRows specifies the number of rows, nColumns + * specifies the number of columns, and pData points to the + * data array. + * + * \par Size Checking + * By default all of the matrix functions perform size checking on the input and + * output matrices. For example, the matrix addition function verifies that the + * two input matrices and the output matrix all have the same number of rows and + * columns. If the size check fails the functions return: + *
    + *     ARM_MATH_SIZE_MISMATCH
    + * 
    + * Otherwise the functions return + *
    + *     ARM_MATH_SUCCESS
    + * 
    + * There is some overhead associated with this matrix size checking. + * The matrix size checking is enabled via the \#define + *
    + *     ARM_MATH_MATRIX_CHECK
    + * 
    + * within the library project settings. By default this macro is defined + * and size checking is enabled. By changing the project settings and + * undefining this macro size checking is eliminated and the functions + * run a bit faster. With size checking disabled the functions always + * return ARM_MATH_SUCCESS. + */ + +/** + * @defgroup groupTransforms Transform Functions + */ + +/** + * @defgroup groupController Controller Functions + */ + +/** + * @defgroup groupStats Statistics Functions + */ +/** + * @defgroup groupSupport Support Functions + */ + +/** + * @defgroup groupInterpolation Interpolation Functions + * These functions perform 1- and 2-dimensional interpolation of data. + * Linear interpolation is used for 1-dimensional data and + * bilinear interpolation is used for 2-dimensional data. + */ + +/** + * @defgroup groupExamples Examples + */ +#ifndef _ARM_MATH_H +#define _ARM_MATH_H + +/* Compiler specific diagnostic adjustment */ +#if defined ( __CC_ARM ) + +#elif defined ( __ARMCC_VERSION ) && ( __ARMCC_VERSION >= 6010050 ) + +#elif defined ( __GNUC__ ) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsign-conversion" +#pragma GCC diagnostic ignored "-Wconversion" +#pragma GCC diagnostic ignored "-Wunused-parameter" + +#elif defined ( __ICCARM__ ) + +#elif defined ( __TI_ARM__ ) + +#elif defined ( __CSMC__ ) + +#elif defined ( __TASKING__ ) + +#else + #error Unknown compiler +#endif + + +#define __CMSIS_GENERIC /* disable NVIC and Systick functions */ + +#if defined(ARM_MATH_CM7) + #include "core_cm7.h" + #define ARM_MATH_DSP +#elif defined (ARM_MATH_CM4) + #include "core_cm4.h" + #define ARM_MATH_DSP +#elif defined (ARM_MATH_CM3) + #include "core_cm3.h" +#elif defined (ARM_MATH_CM0) + #include "core_cm0.h" + #define ARM_MATH_CM0_FAMILY +#elif defined (ARM_MATH_CM0PLUS) + #include "core_cm0plus.h" + #define ARM_MATH_CM0_FAMILY +#elif defined (ARM_MATH_ARMV8MBL) + #include "core_armv8mbl.h" + #define ARM_MATH_CM0_FAMILY +#elif defined (ARM_MATH_ARMV8MML) + #include "core_armv8mml.h" + #if (defined (__DSP_PRESENT) && (__DSP_PRESENT == 1)) + #define ARM_MATH_DSP + #endif +#else + #error "Define according the used Cortex core ARM_MATH_CM7, ARM_MATH_CM4, ARM_MATH_CM3, ARM_MATH_CM0PLUS, ARM_MATH_CM0, ARM_MATH_ARMV8MBL, ARM_MATH_ARMV8MML" +#endif + +#undef __CMSIS_GENERIC /* enable NVIC and Systick functions */ +#include "string.h" +#include "math.h" +#ifdef __cplusplus +extern "C" +{ +#endif + + + /** + * @brief Macros required for reciprocal calculation in Normalized LMS + */ + +#define DELTA_Q31 (0x100) +#define DELTA_Q15 0x5 +#define INDEX_MASK 0x0000003F +#ifndef PI + #define PI 3.14159265358979f +#endif + + /** + * @brief Macros required for SINE and COSINE Fast math approximations + */ + +#define FAST_MATH_TABLE_SIZE 512 +#define FAST_MATH_Q31_SHIFT (32 - 10) +#define FAST_MATH_Q15_SHIFT (16 - 10) +#define CONTROLLER_Q31_SHIFT (32 - 9) +#define TABLE_SPACING_Q31 0x400000 +#define TABLE_SPACING_Q15 0x80 + + /** + * @brief Macros required for SINE and COSINE Controller functions + */ + /* 1.31(q31) Fixed value of 2/360 */ + /* -1 to +1 is divided into 360 values so total spacing is (2/360) */ +#define INPUT_SPACING 0xB60B61 + + /** + * @brief Macro for Unaligned Support + */ +#ifndef UNALIGNED_SUPPORT_DISABLE + #define ALIGN4 +#else + #if defined (__GNUC__) + #define ALIGN4 __attribute__((aligned(4))) + #else + #define ALIGN4 __align(4) + #endif +#endif /* #ifndef UNALIGNED_SUPPORT_DISABLE */ + + /** + * @brief Error status returned by some functions in the library. + */ + + typedef enum + { + ARM_MATH_SUCCESS = 0, /**< No error */ + ARM_MATH_ARGUMENT_ERROR = -1, /**< One or more arguments are incorrect */ + ARM_MATH_LENGTH_ERROR = -2, /**< Length of data buffer is incorrect */ + ARM_MATH_SIZE_MISMATCH = -3, /**< Size of matrices is not compatible with the operation. */ + ARM_MATH_NANINF = -4, /**< Not-a-number (NaN) or infinity is generated */ + ARM_MATH_SINGULAR = -5, /**< Generated by matrix inversion if the input matrix is singular and cannot be inverted. */ + ARM_MATH_TEST_FAILURE = -6 /**< Test Failed */ + } arm_status; + + /** + * @brief 8-bit fractional data type in 1.7 format. + */ + typedef int8_t q7_t; + + /** + * @brief 16-bit fractional data type in 1.15 format. + */ + typedef int16_t q15_t; + + /** + * @brief 32-bit fractional data type in 1.31 format. + */ + typedef int32_t q31_t; + + /** + * @brief 64-bit fractional data type in 1.63 format. + */ + typedef int64_t q63_t; + + /** + * @brief 32-bit floating-point type definition. + */ + typedef float float32_t; + + /** + * @brief 64-bit floating-point type definition. + */ + typedef double float64_t; + + /** + * @brief definition to read/write two 16 bit values. + */ +#if defined ( __CC_ARM ) + #define __SIMD32_TYPE int32_t __packed + #define CMSIS_UNUSED __attribute__((unused)) + #define CMSIS_INLINE __attribute__((always_inline)) + +#elif defined ( __ARMCC_VERSION ) && ( __ARMCC_VERSION >= 6010050 ) + #define __SIMD32_TYPE int32_t + #define CMSIS_UNUSED __attribute__((unused)) + #define CMSIS_INLINE __attribute__((always_inline)) + +#elif defined ( __GNUC__ ) + #define __SIMD32_TYPE int32_t + #define CMSIS_UNUSED __attribute__((unused)) + #define CMSIS_INLINE __attribute__((always_inline)) + +#elif defined ( __ICCARM__ ) + #define __SIMD32_TYPE int32_t __packed + #define CMSIS_UNUSED + #define CMSIS_INLINE + +#elif defined ( __TI_ARM__ ) + #define __SIMD32_TYPE int32_t + #define CMSIS_UNUSED __attribute__((unused)) + #define CMSIS_INLINE + +#elif defined ( __CSMC__ ) + #define __SIMD32_TYPE int32_t + #define CMSIS_UNUSED + #define CMSIS_INLINE + +#elif defined ( __TASKING__ ) + #define __SIMD32_TYPE __unaligned int32_t + #define CMSIS_UNUSED + #define CMSIS_INLINE + +#else + #error Unknown compiler +#endif + +#define __SIMD32(addr) (*(__SIMD32_TYPE **) & (addr)) +#define __SIMD32_CONST(addr) ((__SIMD32_TYPE *)(addr)) +#define _SIMD32_OFFSET(addr) (*(__SIMD32_TYPE *) (addr)) +#define __SIMD64(addr) (*(int64_t **) & (addr)) + +#if !defined (ARM_MATH_DSP) + /** + * @brief definition to pack two 16 bit values. + */ +#define __PKHBT(ARG1, ARG2, ARG3) ( (((int32_t)(ARG1) << 0) & (int32_t)0x0000FFFF) | \ + (((int32_t)(ARG2) << ARG3) & (int32_t)0xFFFF0000) ) +#define __PKHTB(ARG1, ARG2, ARG3) ( (((int32_t)(ARG1) << 0) & (int32_t)0xFFFF0000) | \ + (((int32_t)(ARG2) >> ARG3) & (int32_t)0x0000FFFF) ) + +#endif /* !defined (ARM_MATH_DSP) */ + + /** + * @brief definition to pack four 8 bit values. + */ +#ifndef ARM_MATH_BIG_ENDIAN + +#define __PACKq7(v0,v1,v2,v3) ( (((int32_t)(v0) << 0) & (int32_t)0x000000FF) | \ + (((int32_t)(v1) << 8) & (int32_t)0x0000FF00) | \ + (((int32_t)(v2) << 16) & (int32_t)0x00FF0000) | \ + (((int32_t)(v3) << 24) & (int32_t)0xFF000000) ) +#else + +#define __PACKq7(v0,v1,v2,v3) ( (((int32_t)(v3) << 0) & (int32_t)0x000000FF) | \ + (((int32_t)(v2) << 8) & (int32_t)0x0000FF00) | \ + (((int32_t)(v1) << 16) & (int32_t)0x00FF0000) | \ + (((int32_t)(v0) << 24) & (int32_t)0xFF000000) ) + +#endif + + + /** + * @brief Clips Q63 to Q31 values. + */ + CMSIS_INLINE __STATIC_INLINE q31_t clip_q63_to_q31( + q63_t x) + { + return ((q31_t) (x >> 32) != ((q31_t) x >> 31)) ? + ((0x7FFFFFFF ^ ((q31_t) (x >> 63)))) : (q31_t) x; + } + + /** + * @brief Clips Q63 to Q15 values. + */ + CMSIS_INLINE __STATIC_INLINE q15_t clip_q63_to_q15( + q63_t x) + { + return ((q31_t) (x >> 32) != ((q31_t) x >> 31)) ? + ((0x7FFF ^ ((q15_t) (x >> 63)))) : (q15_t) (x >> 15); + } + + /** + * @brief Clips Q31 to Q7 values. + */ + CMSIS_INLINE __STATIC_INLINE q7_t clip_q31_to_q7( + q31_t x) + { + return ((q31_t) (x >> 24) != ((q31_t) x >> 23)) ? + ((0x7F ^ ((q7_t) (x >> 31)))) : (q7_t) x; + } + + /** + * @brief Clips Q31 to Q15 values. + */ + CMSIS_INLINE __STATIC_INLINE q15_t clip_q31_to_q15( + q31_t x) + { + return ((q31_t) (x >> 16) != ((q31_t) x >> 15)) ? + ((0x7FFF ^ ((q15_t) (x >> 31)))) : (q15_t) x; + } + + /** + * @brief Multiplies 32 X 64 and returns 32 bit result in 2.30 format. + */ + + CMSIS_INLINE __STATIC_INLINE q63_t mult32x64( + q63_t x, + q31_t y) + { + return ((((q63_t) (x & 0x00000000FFFFFFFF) * y) >> 32) + + (((q63_t) (x >> 32) * y))); + } + + /** + * @brief Function to Calculates 1/in (reciprocal) value of Q31 Data type. + */ + + CMSIS_INLINE __STATIC_INLINE uint32_t arm_recip_q31( + q31_t in, + q31_t * dst, + q31_t * pRecipTable) + { + q31_t out; + uint32_t tempVal; + uint32_t index, i; + uint32_t signBits; + + if (in > 0) + { + signBits = ((uint32_t) (__CLZ( in) - 1)); + } + else + { + signBits = ((uint32_t) (__CLZ(-in) - 1)); + } + + /* Convert input sample to 1.31 format */ + in = (in << signBits); + + /* calculation of index for initial approximated Val */ + index = (uint32_t)(in >> 24); + index = (index & INDEX_MASK); + + /* 1.31 with exp 1 */ + out = pRecipTable[index]; + + /* calculation of reciprocal value */ + /* running approximation for two iterations */ + for (i = 0U; i < 2U; i++) + { + tempVal = (uint32_t) (((q63_t) in * out) >> 31); + tempVal = 0x7FFFFFFFu - tempVal; + /* 1.31 with exp 1 */ + /* out = (q31_t) (((q63_t) out * tempVal) >> 30); */ + out = clip_q63_to_q31(((q63_t) out * tempVal) >> 30); + } + + /* write output */ + *dst = out; + + /* return num of signbits of out = 1/in value */ + return (signBits + 1U); + } + + + /** + * @brief Function to Calculates 1/in (reciprocal) value of Q15 Data type. + */ + CMSIS_INLINE __STATIC_INLINE uint32_t arm_recip_q15( + q15_t in, + q15_t * dst, + q15_t * pRecipTable) + { + q15_t out = 0; + uint32_t tempVal = 0; + uint32_t index = 0, i = 0; + uint32_t signBits = 0; + + if (in > 0) + { + signBits = ((uint32_t)(__CLZ( in) - 17)); + } + else + { + signBits = ((uint32_t)(__CLZ(-in) - 17)); + } + + /* Convert input sample to 1.15 format */ + in = (in << signBits); + + /* calculation of index for initial approximated Val */ + index = (uint32_t)(in >> 8); + index = (index & INDEX_MASK); + + /* 1.15 with exp 1 */ + out = pRecipTable[index]; + + /* calculation of reciprocal value */ + /* running approximation for two iterations */ + for (i = 0U; i < 2U; i++) + { + tempVal = (uint32_t) (((q31_t) in * out) >> 15); + tempVal = 0x7FFFu - tempVal; + /* 1.15 with exp 1 */ + out = (q15_t) (((q31_t) out * tempVal) >> 14); + /* out = clip_q31_to_q15(((q31_t) out * tempVal) >> 14); */ + } + + /* write output */ + *dst = out; + + /* return num of signbits of out = 1/in value */ + return (signBits + 1); + } + + +/* + * @brief C custom defined intrinsic function for M3 and M0 processors + */ +#if !defined (ARM_MATH_DSP) + + /* + * @brief C custom defined QADD8 for M3 and M0 processors + */ + CMSIS_INLINE __STATIC_INLINE uint32_t __QADD8( + uint32_t x, + uint32_t y) + { + q31_t r, s, t, u; + + r = __SSAT(((((q31_t)x << 24) >> 24) + (((q31_t)y << 24) >> 24)), 8) & (int32_t)0x000000FF; + s = __SSAT(((((q31_t)x << 16) >> 24) + (((q31_t)y << 16) >> 24)), 8) & (int32_t)0x000000FF; + t = __SSAT(((((q31_t)x << 8) >> 24) + (((q31_t)y << 8) >> 24)), 8) & (int32_t)0x000000FF; + u = __SSAT(((((q31_t)x ) >> 24) + (((q31_t)y ) >> 24)), 8) & (int32_t)0x000000FF; + + return ((uint32_t)((u << 24) | (t << 16) | (s << 8) | (r ))); + } + + + /* + * @brief C custom defined QSUB8 for M3 and M0 processors + */ + CMSIS_INLINE __STATIC_INLINE uint32_t __QSUB8( + uint32_t x, + uint32_t y) + { + q31_t r, s, t, u; + + r = __SSAT(((((q31_t)x << 24) >> 24) - (((q31_t)y << 24) >> 24)), 8) & (int32_t)0x000000FF; + s = __SSAT(((((q31_t)x << 16) >> 24) - (((q31_t)y << 16) >> 24)), 8) & (int32_t)0x000000FF; + t = __SSAT(((((q31_t)x << 8) >> 24) - (((q31_t)y << 8) >> 24)), 8) & (int32_t)0x000000FF; + u = __SSAT(((((q31_t)x ) >> 24) - (((q31_t)y ) >> 24)), 8) & (int32_t)0x000000FF; + + return ((uint32_t)((u << 24) | (t << 16) | (s << 8) | (r ))); + } + + + /* + * @brief C custom defined QADD16 for M3 and M0 processors + */ + CMSIS_INLINE __STATIC_INLINE uint32_t __QADD16( + uint32_t x, + uint32_t y) + { +/* q31_t r, s; without initialisation 'arm_offset_q15 test' fails but 'intrinsic' tests pass! for armCC */ + q31_t r = 0, s = 0; + + r = __SSAT(((((q31_t)x << 16) >> 16) + (((q31_t)y << 16) >> 16)), 16) & (int32_t)0x0000FFFF; + s = __SSAT(((((q31_t)x ) >> 16) + (((q31_t)y ) >> 16)), 16) & (int32_t)0x0000FFFF; + + return ((uint32_t)((s << 16) | (r ))); + } + + + /* + * @brief C custom defined SHADD16 for M3 and M0 processors + */ + CMSIS_INLINE __STATIC_INLINE uint32_t __SHADD16( + uint32_t x, + uint32_t y) + { + q31_t r, s; + + r = (((((q31_t)x << 16) >> 16) + (((q31_t)y << 16) >> 16)) >> 1) & (int32_t)0x0000FFFF; + s = (((((q31_t)x ) >> 16) + (((q31_t)y ) >> 16)) >> 1) & (int32_t)0x0000FFFF; + + return ((uint32_t)((s << 16) | (r ))); + } + + + /* + * @brief C custom defined QSUB16 for M3 and M0 processors + */ + CMSIS_INLINE __STATIC_INLINE uint32_t __QSUB16( + uint32_t x, + uint32_t y) + { + q31_t r, s; + + r = __SSAT(((((q31_t)x << 16) >> 16) - (((q31_t)y << 16) >> 16)), 16) & (int32_t)0x0000FFFF; + s = __SSAT(((((q31_t)x ) >> 16) - (((q31_t)y ) >> 16)), 16) & (int32_t)0x0000FFFF; + + return ((uint32_t)((s << 16) | (r ))); + } + + + /* + * @brief C custom defined SHSUB16 for M3 and M0 processors + */ + CMSIS_INLINE __STATIC_INLINE uint32_t __SHSUB16( + uint32_t x, + uint32_t y) + { + q31_t r, s; + + r = (((((q31_t)x << 16) >> 16) - (((q31_t)y << 16) >> 16)) >> 1) & (int32_t)0x0000FFFF; + s = (((((q31_t)x ) >> 16) - (((q31_t)y ) >> 16)) >> 1) & (int32_t)0x0000FFFF; + + return ((uint32_t)((s << 16) | (r ))); + } + + + /* + * @brief C custom defined QASX for M3 and M0 processors + */ + CMSIS_INLINE __STATIC_INLINE uint32_t __QASX( + uint32_t x, + uint32_t y) + { + q31_t r, s; + + r = __SSAT(((((q31_t)x << 16) >> 16) - (((q31_t)y ) >> 16)), 16) & (int32_t)0x0000FFFF; + s = __SSAT(((((q31_t)x ) >> 16) + (((q31_t)y << 16) >> 16)), 16) & (int32_t)0x0000FFFF; + + return ((uint32_t)((s << 16) | (r ))); + } + + + /* + * @brief C custom defined SHASX for M3 and M0 processors + */ + CMSIS_INLINE __STATIC_INLINE uint32_t __SHASX( + uint32_t x, + uint32_t y) + { + q31_t r, s; + + r = (((((q31_t)x << 16) >> 16) - (((q31_t)y ) >> 16)) >> 1) & (int32_t)0x0000FFFF; + s = (((((q31_t)x ) >> 16) + (((q31_t)y << 16) >> 16)) >> 1) & (int32_t)0x0000FFFF; + + return ((uint32_t)((s << 16) | (r ))); + } + + + /* + * @brief C custom defined QSAX for M3 and M0 processors + */ + CMSIS_INLINE __STATIC_INLINE uint32_t __QSAX( + uint32_t x, + uint32_t y) + { + q31_t r, s; + + r = __SSAT(((((q31_t)x << 16) >> 16) + (((q31_t)y ) >> 16)), 16) & (int32_t)0x0000FFFF; + s = __SSAT(((((q31_t)x ) >> 16) - (((q31_t)y << 16) >> 16)), 16) & (int32_t)0x0000FFFF; + + return ((uint32_t)((s << 16) | (r ))); + } + + + /* + * @brief C custom defined SHSAX for M3 and M0 processors + */ + CMSIS_INLINE __STATIC_INLINE uint32_t __SHSAX( + uint32_t x, + uint32_t y) + { + q31_t r, s; + + r = (((((q31_t)x << 16) >> 16) + (((q31_t)y ) >> 16)) >> 1) & (int32_t)0x0000FFFF; + s = (((((q31_t)x ) >> 16) - (((q31_t)y << 16) >> 16)) >> 1) & (int32_t)0x0000FFFF; + + return ((uint32_t)((s << 16) | (r ))); + } + + + /* + * @brief C custom defined SMUSDX for M3 and M0 processors + */ + CMSIS_INLINE __STATIC_INLINE uint32_t __SMUSDX( + uint32_t x, + uint32_t y) + { + return ((uint32_t)(((((q31_t)x << 16) >> 16) * (((q31_t)y ) >> 16)) - + ((((q31_t)x ) >> 16) * (((q31_t)y << 16) >> 16)) )); + } + + /* + * @brief C custom defined SMUADX for M3 and M0 processors + */ + CMSIS_INLINE __STATIC_INLINE uint32_t __SMUADX( + uint32_t x, + uint32_t y) + { + return ((uint32_t)(((((q31_t)x << 16) >> 16) * (((q31_t)y ) >> 16)) + + ((((q31_t)x ) >> 16) * (((q31_t)y << 16) >> 16)) )); + } + + + /* + * @brief C custom defined QADD for M3 and M0 processors + */ + CMSIS_INLINE __STATIC_INLINE int32_t __QADD( + int32_t x, + int32_t y) + { + return ((int32_t)(clip_q63_to_q31((q63_t)x + (q31_t)y))); + } + + + /* + * @brief C custom defined QSUB for M3 and M0 processors + */ + CMSIS_INLINE __STATIC_INLINE int32_t __QSUB( + int32_t x, + int32_t y) + { + return ((int32_t)(clip_q63_to_q31((q63_t)x - (q31_t)y))); + } + + + /* + * @brief C custom defined SMLAD for M3 and M0 processors + */ + CMSIS_INLINE __STATIC_INLINE uint32_t __SMLAD( + uint32_t x, + uint32_t y, + uint32_t sum) + { + return ((uint32_t)(((((q31_t)x << 16) >> 16) * (((q31_t)y << 16) >> 16)) + + ((((q31_t)x ) >> 16) * (((q31_t)y ) >> 16)) + + ( ((q31_t)sum ) ) )); + } + + + /* + * @brief C custom defined SMLADX for M3 and M0 processors + */ + CMSIS_INLINE __STATIC_INLINE uint32_t __SMLADX( + uint32_t x, + uint32_t y, + uint32_t sum) + { + return ((uint32_t)(((((q31_t)x << 16) >> 16) * (((q31_t)y ) >> 16)) + + ((((q31_t)x ) >> 16) * (((q31_t)y << 16) >> 16)) + + ( ((q31_t)sum ) ) )); + } + + + /* + * @brief C custom defined SMLSDX for M3 and M0 processors + */ + CMSIS_INLINE __STATIC_INLINE uint32_t __SMLSDX( + uint32_t x, + uint32_t y, + uint32_t sum) + { + return ((uint32_t)(((((q31_t)x << 16) >> 16) * (((q31_t)y ) >> 16)) - + ((((q31_t)x ) >> 16) * (((q31_t)y << 16) >> 16)) + + ( ((q31_t)sum ) ) )); + } + + + /* + * @brief C custom defined SMLALD for M3 and M0 processors + */ + CMSIS_INLINE __STATIC_INLINE uint64_t __SMLALD( + uint32_t x, + uint32_t y, + uint64_t sum) + { +/* return (sum + ((q15_t) (x >> 16) * (q15_t) (y >> 16)) + ((q15_t) x * (q15_t) y)); */ + return ((uint64_t)(((((q31_t)x << 16) >> 16) * (((q31_t)y << 16) >> 16)) + + ((((q31_t)x ) >> 16) * (((q31_t)y ) >> 16)) + + ( ((q63_t)sum ) ) )); + } + + + /* + * @brief C custom defined SMLALDX for M3 and M0 processors + */ + CMSIS_INLINE __STATIC_INLINE uint64_t __SMLALDX( + uint32_t x, + uint32_t y, + uint64_t sum) + { +/* return (sum + ((q15_t) (x >> 16) * (q15_t) y)) + ((q15_t) x * (q15_t) (y >> 16)); */ + return ((uint64_t)(((((q31_t)x << 16) >> 16) * (((q31_t)y ) >> 16)) + + ((((q31_t)x ) >> 16) * (((q31_t)y << 16) >> 16)) + + ( ((q63_t)sum ) ) )); + } + + + /* + * @brief C custom defined SMUAD for M3 and M0 processors + */ + CMSIS_INLINE __STATIC_INLINE uint32_t __SMUAD( + uint32_t x, + uint32_t y) + { + return ((uint32_t)(((((q31_t)x << 16) >> 16) * (((q31_t)y << 16) >> 16)) + + ((((q31_t)x ) >> 16) * (((q31_t)y ) >> 16)) )); + } + + + /* + * @brief C custom defined SMUSD for M3 and M0 processors + */ + CMSIS_INLINE __STATIC_INLINE uint32_t __SMUSD( + uint32_t x, + uint32_t y) + { + return ((uint32_t)(((((q31_t)x << 16) >> 16) * (((q31_t)y << 16) >> 16)) - + ((((q31_t)x ) >> 16) * (((q31_t)y ) >> 16)) )); + } + + + /* + * @brief C custom defined SXTB16 for M3 and M0 processors + */ + CMSIS_INLINE __STATIC_INLINE uint32_t __SXTB16( + uint32_t x) + { + return ((uint32_t)(((((q31_t)x << 24) >> 24) & (q31_t)0x0000FFFF) | + ((((q31_t)x << 8) >> 8) & (q31_t)0xFFFF0000) )); + } + + /* + * @brief C custom defined SMMLA for M3 and M0 processors + */ + CMSIS_INLINE __STATIC_INLINE int32_t __SMMLA( + int32_t x, + int32_t y, + int32_t sum) + { + return (sum + (int32_t) (((int64_t) x * y) >> 32)); + } + +#endif /* !defined (ARM_MATH_DSP) */ + + + /** + * @brief Instance structure for the Q7 FIR filter. + */ + typedef struct + { + uint16_t numTaps; /**< number of filter coefficients in the filter. */ + q7_t *pState; /**< points to the state variable array. The array is of length numTaps+blockSize-1. */ + q7_t *pCoeffs; /**< points to the coefficient array. The array is of length numTaps.*/ + } arm_fir_instance_q7; + + /** + * @brief Instance structure for the Q15 FIR filter. + */ + typedef struct + { + uint16_t numTaps; /**< number of filter coefficients in the filter. */ + q15_t *pState; /**< points to the state variable array. The array is of length numTaps+blockSize-1. */ + q15_t *pCoeffs; /**< points to the coefficient array. The array is of length numTaps.*/ + } arm_fir_instance_q15; + + /** + * @brief Instance structure for the Q31 FIR filter. + */ + typedef struct + { + uint16_t numTaps; /**< number of filter coefficients in the filter. */ + q31_t *pState; /**< points to the state variable array. The array is of length numTaps+blockSize-1. */ + q31_t *pCoeffs; /**< points to the coefficient array. The array is of length numTaps. */ + } arm_fir_instance_q31; + + /** + * @brief Instance structure for the floating-point FIR filter. + */ + typedef struct + { + uint16_t numTaps; /**< number of filter coefficients in the filter. */ + float32_t *pState; /**< points to the state variable array. The array is of length numTaps+blockSize-1. */ + float32_t *pCoeffs; /**< points to the coefficient array. The array is of length numTaps. */ + } arm_fir_instance_f32; + + + /** + * @brief Processing function for the Q7 FIR filter. + * @param[in] S points to an instance of the Q7 FIR filter structure. + * @param[in] pSrc points to the block of input data. + * @param[out] pDst points to the block of output data. + * @param[in] blockSize number of samples to process. + */ + void arm_fir_q7( + const arm_fir_instance_q7 * S, + q7_t * pSrc, + q7_t * pDst, + uint32_t blockSize); + + + /** + * @brief Initialization function for the Q7 FIR filter. + * @param[in,out] S points to an instance of the Q7 FIR structure. + * @param[in] numTaps Number of filter coefficients in the filter. + * @param[in] pCoeffs points to the filter coefficients. + * @param[in] pState points to the state buffer. + * @param[in] blockSize number of samples that are processed. + */ + void arm_fir_init_q7( + arm_fir_instance_q7 * S, + uint16_t numTaps, + q7_t * pCoeffs, + q7_t * pState, + uint32_t blockSize); + + + /** + * @brief Processing function for the Q15 FIR filter. + * @param[in] S points to an instance of the Q15 FIR structure. + * @param[in] pSrc points to the block of input data. + * @param[out] pDst points to the block of output data. + * @param[in] blockSize number of samples to process. + */ + void arm_fir_q15( + const arm_fir_instance_q15 * S, + q15_t * pSrc, + q15_t * pDst, + uint32_t blockSize); + + + /** + * @brief Processing function for the fast Q15 FIR filter for Cortex-M3 and Cortex-M4. + * @param[in] S points to an instance of the Q15 FIR filter structure. + * @param[in] pSrc points to the block of input data. + * @param[out] pDst points to the block of output data. + * @param[in] blockSize number of samples to process. + */ + void arm_fir_fast_q15( + const arm_fir_instance_q15 * S, + q15_t * pSrc, + q15_t * pDst, + uint32_t blockSize); + + + /** + * @brief Initialization function for the Q15 FIR filter. + * @param[in,out] S points to an instance of the Q15 FIR filter structure. + * @param[in] numTaps Number of filter coefficients in the filter. Must be even and greater than or equal to 4. + * @param[in] pCoeffs points to the filter coefficients. + * @param[in] pState points to the state buffer. + * @param[in] blockSize number of samples that are processed at a time. + * @return The function returns ARM_MATH_SUCCESS if initialization was successful or ARM_MATH_ARGUMENT_ERROR if + * numTaps is not a supported value. + */ + arm_status arm_fir_init_q15( + arm_fir_instance_q15 * S, + uint16_t numTaps, + q15_t * pCoeffs, + q15_t * pState, + uint32_t blockSize); + + + /** + * @brief Processing function for the Q31 FIR filter. + * @param[in] S points to an instance of the Q31 FIR filter structure. + * @param[in] pSrc points to the block of input data. + * @param[out] pDst points to the block of output data. + * @param[in] blockSize number of samples to process. + */ + void arm_fir_q31( + const arm_fir_instance_q31 * S, + q31_t * pSrc, + q31_t * pDst, + uint32_t blockSize); + + + /** + * @brief Processing function for the fast Q31 FIR filter for Cortex-M3 and Cortex-M4. + * @param[in] S points to an instance of the Q31 FIR structure. + * @param[in] pSrc points to the block of input data. + * @param[out] pDst points to the block of output data. + * @param[in] blockSize number of samples to process. + */ + void arm_fir_fast_q31( + const arm_fir_instance_q31 * S, + q31_t * pSrc, + q31_t * pDst, + uint32_t blockSize); + + + /** + * @brief Initialization function for the Q31 FIR filter. + * @param[in,out] S points to an instance of the Q31 FIR structure. + * @param[in] numTaps Number of filter coefficients in the filter. + * @param[in] pCoeffs points to the filter coefficients. + * @param[in] pState points to the state buffer. + * @param[in] blockSize number of samples that are processed at a time. + */ + void arm_fir_init_q31( + arm_fir_instance_q31 * S, + uint16_t numTaps, + q31_t * pCoeffs, + q31_t * pState, + uint32_t blockSize); + + + /** + * @brief Processing function for the floating-point FIR filter. + * @param[in] S points to an instance of the floating-point FIR structure. + * @param[in] pSrc points to the block of input data. + * @param[out] pDst points to the block of output data. + * @param[in] blockSize number of samples to process. + */ + void arm_fir_f32( + const arm_fir_instance_f32 * S, + float32_t * pSrc, + float32_t * pDst, + uint32_t blockSize); + + + /** + * @brief Initialization function for the floating-point FIR filter. + * @param[in,out] S points to an instance of the floating-point FIR filter structure. + * @param[in] numTaps Number of filter coefficients in the filter. + * @param[in] pCoeffs points to the filter coefficients. + * @param[in] pState points to the state buffer. + * @param[in] blockSize number of samples that are processed at a time. + */ + void arm_fir_init_f32( + arm_fir_instance_f32 * S, + uint16_t numTaps, + float32_t * pCoeffs, + float32_t * pState, + uint32_t blockSize); + + + /** + * @brief Instance structure for the Q15 Biquad cascade filter. + */ + typedef struct + { + int8_t numStages; /**< number of 2nd order stages in the filter. Overall order is 2*numStages. */ + q15_t *pState; /**< Points to the array of state coefficients. The array is of length 4*numStages. */ + q15_t *pCoeffs; /**< Points to the array of coefficients. The array is of length 5*numStages. */ + int8_t postShift; /**< Additional shift, in bits, applied to each output sample. */ + } arm_biquad_casd_df1_inst_q15; + + /** + * @brief Instance structure for the Q31 Biquad cascade filter. + */ + typedef struct + { + uint32_t numStages; /**< number of 2nd order stages in the filter. Overall order is 2*numStages. */ + q31_t *pState; /**< Points to the array of state coefficients. The array is of length 4*numStages. */ + q31_t *pCoeffs; /**< Points to the array of coefficients. The array is of length 5*numStages. */ + uint8_t postShift; /**< Additional shift, in bits, applied to each output sample. */ + } arm_biquad_casd_df1_inst_q31; + + /** + * @brief Instance structure for the floating-point Biquad cascade filter. + */ + typedef struct + { + uint32_t numStages; /**< number of 2nd order stages in the filter. Overall order is 2*numStages. */ + float32_t *pState; /**< Points to the array of state coefficients. The array is of length 4*numStages. */ + float32_t *pCoeffs; /**< Points to the array of coefficients. The array is of length 5*numStages. */ + } arm_biquad_casd_df1_inst_f32; + + + /** + * @brief Processing function for the Q15 Biquad cascade filter. + * @param[in] S points to an instance of the Q15 Biquad cascade structure. + * @param[in] pSrc points to the block of input data. + * @param[out] pDst points to the block of output data. + * @param[in] blockSize number of samples to process. + */ + void arm_biquad_cascade_df1_q15( + const arm_biquad_casd_df1_inst_q15 * S, + q15_t * pSrc, + q15_t * pDst, + uint32_t blockSize); + + + /** + * @brief Initialization function for the Q15 Biquad cascade filter. + * @param[in,out] S points to an instance of the Q15 Biquad cascade structure. + * @param[in] numStages number of 2nd order stages in the filter. + * @param[in] pCoeffs points to the filter coefficients. + * @param[in] pState points to the state buffer. + * @param[in] postShift Shift to be applied to the output. Varies according to the coefficients format + */ + void arm_biquad_cascade_df1_init_q15( + arm_biquad_casd_df1_inst_q15 * S, + uint8_t numStages, + q15_t * pCoeffs, + q15_t * pState, + int8_t postShift); + + + /** + * @brief Fast but less precise processing function for the Q15 Biquad cascade filter for Cortex-M3 and Cortex-M4. + * @param[in] S points to an instance of the Q15 Biquad cascade structure. + * @param[in] pSrc points to the block of input data. + * @param[out] pDst points to the block of output data. + * @param[in] blockSize number of samples to process. + */ + void arm_biquad_cascade_df1_fast_q15( + const arm_biquad_casd_df1_inst_q15 * S, + q15_t * pSrc, + q15_t * pDst, + uint32_t blockSize); + + + /** + * @brief Processing function for the Q31 Biquad cascade filter + * @param[in] S points to an instance of the Q31 Biquad cascade structure. + * @param[in] pSrc points to the block of input data. + * @param[out] pDst points to the block of output data. + * @param[in] blockSize number of samples to process. + */ + void arm_biquad_cascade_df1_q31( + const arm_biquad_casd_df1_inst_q31 * S, + q31_t * pSrc, + q31_t * pDst, + uint32_t blockSize); + + + /** + * @brief Fast but less precise processing function for the Q31 Biquad cascade filter for Cortex-M3 and Cortex-M4. + * @param[in] S points to an instance of the Q31 Biquad cascade structure. + * @param[in] pSrc points to the block of input data. + * @param[out] pDst points to the block of output data. + * @param[in] blockSize number of samples to process. + */ + void arm_biquad_cascade_df1_fast_q31( + const arm_biquad_casd_df1_inst_q31 * S, + q31_t * pSrc, + q31_t * pDst, + uint32_t blockSize); + + + /** + * @brief Initialization function for the Q31 Biquad cascade filter. + * @param[in,out] S points to an instance of the Q31 Biquad cascade structure. + * @param[in] numStages number of 2nd order stages in the filter. + * @param[in] pCoeffs points to the filter coefficients. + * @param[in] pState points to the state buffer. + * @param[in] postShift Shift to be applied to the output. Varies according to the coefficients format + */ + void arm_biquad_cascade_df1_init_q31( + arm_biquad_casd_df1_inst_q31 * S, + uint8_t numStages, + q31_t * pCoeffs, + q31_t * pState, + int8_t postShift); + + + /** + * @brief Processing function for the floating-point Biquad cascade filter. + * @param[in] S points to an instance of the floating-point Biquad cascade structure. + * @param[in] pSrc points to the block of input data. + * @param[out] pDst points to the block of output data. + * @param[in] blockSize number of samples to process. + */ + void arm_biquad_cascade_df1_f32( + const arm_biquad_casd_df1_inst_f32 * S, + float32_t * pSrc, + float32_t * pDst, + uint32_t blockSize); + + + /** + * @brief Initialization function for the floating-point Biquad cascade filter. + * @param[in,out] S points to an instance of the floating-point Biquad cascade structure. + * @param[in] numStages number of 2nd order stages in the filter. + * @param[in] pCoeffs points to the filter coefficients. + * @param[in] pState points to the state buffer. + */ + void arm_biquad_cascade_df1_init_f32( + arm_biquad_casd_df1_inst_f32 * S, + uint8_t numStages, + float32_t * pCoeffs, + float32_t * pState); + + + /** + * @brief Instance structure for the floating-point matrix structure. + */ + typedef struct + { + uint16_t numRows; /**< number of rows of the matrix. */ + uint16_t numCols; /**< number of columns of the matrix. */ + float32_t *pData; /**< points to the data of the matrix. */ + } arm_matrix_instance_f32; + + + /** + * @brief Instance structure for the floating-point matrix structure. + */ + typedef struct + { + uint16_t numRows; /**< number of rows of the matrix. */ + uint16_t numCols; /**< number of columns of the matrix. */ + float64_t *pData; /**< points to the data of the matrix. */ + } arm_matrix_instance_f64; + + /** + * @brief Instance structure for the Q15 matrix structure. + */ + typedef struct + { + uint16_t numRows; /**< number of rows of the matrix. */ + uint16_t numCols; /**< number of columns of the matrix. */ + q15_t *pData; /**< points to the data of the matrix. */ + } arm_matrix_instance_q15; + + /** + * @brief Instance structure for the Q31 matrix structure. + */ + typedef struct + { + uint16_t numRows; /**< number of rows of the matrix. */ + uint16_t numCols; /**< number of columns of the matrix. */ + q31_t *pData; /**< points to the data of the matrix. */ + } arm_matrix_instance_q31; + + + /** + * @brief Floating-point matrix addition. + * @param[in] pSrcA points to the first input matrix structure + * @param[in] pSrcB points to the second input matrix structure + * @param[out] pDst points to output matrix structure + * @return The function returns either + * ARM_MATH_SIZE_MISMATCH or ARM_MATH_SUCCESS based on the outcome of size checking. + */ + arm_status arm_mat_add_f32( + const arm_matrix_instance_f32 * pSrcA, + const arm_matrix_instance_f32 * pSrcB, + arm_matrix_instance_f32 * pDst); + + + /** + * @brief Q15 matrix addition. + * @param[in] pSrcA points to the first input matrix structure + * @param[in] pSrcB points to the second input matrix structure + * @param[out] pDst points to output matrix structure + * @return The function returns either + * ARM_MATH_SIZE_MISMATCH or ARM_MATH_SUCCESS based on the outcome of size checking. + */ + arm_status arm_mat_add_q15( + const arm_matrix_instance_q15 * pSrcA, + const arm_matrix_instance_q15 * pSrcB, + arm_matrix_instance_q15 * pDst); + + + /** + * @brief Q31 matrix addition. + * @param[in] pSrcA points to the first input matrix structure + * @param[in] pSrcB points to the second input matrix structure + * @param[out] pDst points to output matrix structure + * @return The function returns either + * ARM_MATH_SIZE_MISMATCH or ARM_MATH_SUCCESS based on the outcome of size checking. + */ + arm_status arm_mat_add_q31( + const arm_matrix_instance_q31 * pSrcA, + const arm_matrix_instance_q31 * pSrcB, + arm_matrix_instance_q31 * pDst); + + + /** + * @brief Floating-point, complex, matrix multiplication. + * @param[in] pSrcA points to the first input matrix structure + * @param[in] pSrcB points to the second input matrix structure + * @param[out] pDst points to output matrix structure + * @return The function returns either + * ARM_MATH_SIZE_MISMATCH or ARM_MATH_SUCCESS based on the outcome of size checking. + */ + arm_status arm_mat_cmplx_mult_f32( + const arm_matrix_instance_f32 * pSrcA, + const arm_matrix_instance_f32 * pSrcB, + arm_matrix_instance_f32 * pDst); + + + /** + * @brief Q15, complex, matrix multiplication. + * @param[in] pSrcA points to the first input matrix structure + * @param[in] pSrcB points to the second input matrix structure + * @param[out] pDst points to output matrix structure + * @return The function returns either + * ARM_MATH_SIZE_MISMATCH or ARM_MATH_SUCCESS based on the outcome of size checking. + */ + arm_status arm_mat_cmplx_mult_q15( + const arm_matrix_instance_q15 * pSrcA, + const arm_matrix_instance_q15 * pSrcB, + arm_matrix_instance_q15 * pDst, + q15_t * pScratch); + + + /** + * @brief Q31, complex, matrix multiplication. + * @param[in] pSrcA points to the first input matrix structure + * @param[in] pSrcB points to the second input matrix structure + * @param[out] pDst points to output matrix structure + * @return The function returns either + * ARM_MATH_SIZE_MISMATCH or ARM_MATH_SUCCESS based on the outcome of size checking. + */ + arm_status arm_mat_cmplx_mult_q31( + const arm_matrix_instance_q31 * pSrcA, + const arm_matrix_instance_q31 * pSrcB, + arm_matrix_instance_q31 * pDst); + + + /** + * @brief Floating-point matrix transpose. + * @param[in] pSrc points to the input matrix + * @param[out] pDst points to the output matrix + * @return The function returns either ARM_MATH_SIZE_MISMATCH + * or ARM_MATH_SUCCESS based on the outcome of size checking. + */ + arm_status arm_mat_trans_f32( + const arm_matrix_instance_f32 * pSrc, + arm_matrix_instance_f32 * pDst); + + + /** + * @brief Q15 matrix transpose. + * @param[in] pSrc points to the input matrix + * @param[out] pDst points to the output matrix + * @return The function returns either ARM_MATH_SIZE_MISMATCH + * or ARM_MATH_SUCCESS based on the outcome of size checking. + */ + arm_status arm_mat_trans_q15( + const arm_matrix_instance_q15 * pSrc, + arm_matrix_instance_q15 * pDst); + + + /** + * @brief Q31 matrix transpose. + * @param[in] pSrc points to the input matrix + * @param[out] pDst points to the output matrix + * @return The function returns either ARM_MATH_SIZE_MISMATCH + * or ARM_MATH_SUCCESS based on the outcome of size checking. + */ + arm_status arm_mat_trans_q31( + const arm_matrix_instance_q31 * pSrc, + arm_matrix_instance_q31 * pDst); + + + /** + * @brief Floating-point matrix multiplication + * @param[in] pSrcA points to the first input matrix structure + * @param[in] pSrcB points to the second input matrix structure + * @param[out] pDst points to output matrix structure + * @return The function returns either + * ARM_MATH_SIZE_MISMATCH or ARM_MATH_SUCCESS based on the outcome of size checking. + */ + arm_status arm_mat_mult_f32( + const arm_matrix_instance_f32 * pSrcA, + const arm_matrix_instance_f32 * pSrcB, + arm_matrix_instance_f32 * pDst); + + + /** + * @brief Q15 matrix multiplication + * @param[in] pSrcA points to the first input matrix structure + * @param[in] pSrcB points to the second input matrix structure + * @param[out] pDst points to output matrix structure + * @param[in] pState points to the array for storing intermediate results + * @return The function returns either + * ARM_MATH_SIZE_MISMATCH or ARM_MATH_SUCCESS based on the outcome of size checking. + */ + arm_status arm_mat_mult_q15( + const arm_matrix_instance_q15 * pSrcA, + const arm_matrix_instance_q15 * pSrcB, + arm_matrix_instance_q15 * pDst, + q15_t * pState); + + + /** + * @brief Q15 matrix multiplication (fast variant) for Cortex-M3 and Cortex-M4 + * @param[in] pSrcA points to the first input matrix structure + * @param[in] pSrcB points to the second input matrix structure + * @param[out] pDst points to output matrix structure + * @param[in] pState points to the array for storing intermediate results + * @return The function returns either + * ARM_MATH_SIZE_MISMATCH or ARM_MATH_SUCCESS based on the outcome of size checking. + */ + arm_status arm_mat_mult_fast_q15( + const arm_matrix_instance_q15 * pSrcA, + const arm_matrix_instance_q15 * pSrcB, + arm_matrix_instance_q15 * pDst, + q15_t * pState); + + + /** + * @brief Q31 matrix multiplication + * @param[in] pSrcA points to the first input matrix structure + * @param[in] pSrcB points to the second input matrix structure + * @param[out] pDst points to output matrix structure + * @return The function returns either + * ARM_MATH_SIZE_MISMATCH or ARM_MATH_SUCCESS based on the outcome of size checking. + */ + arm_status arm_mat_mult_q31( + const arm_matrix_instance_q31 * pSrcA, + const arm_matrix_instance_q31 * pSrcB, + arm_matrix_instance_q31 * pDst); + + + /** + * @brief Q31 matrix multiplication (fast variant) for Cortex-M3 and Cortex-M4 + * @param[in] pSrcA points to the first input matrix structure + * @param[in] pSrcB points to the second input matrix structure + * @param[out] pDst points to output matrix structure + * @return The function returns either + * ARM_MATH_SIZE_MISMATCH or ARM_MATH_SUCCESS based on the outcome of size checking. + */ + arm_status arm_mat_mult_fast_q31( + const arm_matrix_instance_q31 * pSrcA, + const arm_matrix_instance_q31 * pSrcB, + arm_matrix_instance_q31 * pDst); + + + /** + * @brief Floating-point matrix subtraction + * @param[in] pSrcA points to the first input matrix structure + * @param[in] pSrcB points to the second input matrix structure + * @param[out] pDst points to output matrix structure + * @return The function returns either + * ARM_MATH_SIZE_MISMATCH or ARM_MATH_SUCCESS based on the outcome of size checking. + */ + arm_status arm_mat_sub_f32( + const arm_matrix_instance_f32 * pSrcA, + const arm_matrix_instance_f32 * pSrcB, + arm_matrix_instance_f32 * pDst); + + + /** + * @brief Q15 matrix subtraction + * @param[in] pSrcA points to the first input matrix structure + * @param[in] pSrcB points to the second input matrix structure + * @param[out] pDst points to output matrix structure + * @return The function returns either + * ARM_MATH_SIZE_MISMATCH or ARM_MATH_SUCCESS based on the outcome of size checking. + */ + arm_status arm_mat_sub_q15( + const arm_matrix_instance_q15 * pSrcA, + const arm_matrix_instance_q15 * pSrcB, + arm_matrix_instance_q15 * pDst); + + + /** + * @brief Q31 matrix subtraction + * @param[in] pSrcA points to the first input matrix structure + * @param[in] pSrcB points to the second input matrix structure + * @param[out] pDst points to output matrix structure + * @return The function returns either + * ARM_MATH_SIZE_MISMATCH or ARM_MATH_SUCCESS based on the outcome of size checking. + */ + arm_status arm_mat_sub_q31( + const arm_matrix_instance_q31 * pSrcA, + const arm_matrix_instance_q31 * pSrcB, + arm_matrix_instance_q31 * pDst); + + + /** + * @brief Floating-point matrix scaling. + * @param[in] pSrc points to the input matrix + * @param[in] scale scale factor + * @param[out] pDst points to the output matrix + * @return The function returns either + * ARM_MATH_SIZE_MISMATCH or ARM_MATH_SUCCESS based on the outcome of size checking. + */ + arm_status arm_mat_scale_f32( + const arm_matrix_instance_f32 * pSrc, + float32_t scale, + arm_matrix_instance_f32 * pDst); + + + /** + * @brief Q15 matrix scaling. + * @param[in] pSrc points to input matrix + * @param[in] scaleFract fractional portion of the scale factor + * @param[in] shift number of bits to shift the result by + * @param[out] pDst points to output matrix + * @return The function returns either + * ARM_MATH_SIZE_MISMATCH or ARM_MATH_SUCCESS based on the outcome of size checking. + */ + arm_status arm_mat_scale_q15( + const arm_matrix_instance_q15 * pSrc, + q15_t scaleFract, + int32_t shift, + arm_matrix_instance_q15 * pDst); + + + /** + * @brief Q31 matrix scaling. + * @param[in] pSrc points to input matrix + * @param[in] scaleFract fractional portion of the scale factor + * @param[in] shift number of bits to shift the result by + * @param[out] pDst points to output matrix structure + * @return The function returns either + * ARM_MATH_SIZE_MISMATCH or ARM_MATH_SUCCESS based on the outcome of size checking. + */ + arm_status arm_mat_scale_q31( + const arm_matrix_instance_q31 * pSrc, + q31_t scaleFract, + int32_t shift, + arm_matrix_instance_q31 * pDst); + + + /** + * @brief Q31 matrix initialization. + * @param[in,out] S points to an instance of the floating-point matrix structure. + * @param[in] nRows number of rows in the matrix. + * @param[in] nColumns number of columns in the matrix. + * @param[in] pData points to the matrix data array. + */ + void arm_mat_init_q31( + arm_matrix_instance_q31 * S, + uint16_t nRows, + uint16_t nColumns, + q31_t * pData); + + + /** + * @brief Q15 matrix initialization. + * @param[in,out] S points to an instance of the floating-point matrix structure. + * @param[in] nRows number of rows in the matrix. + * @param[in] nColumns number of columns in the matrix. + * @param[in] pData points to the matrix data array. + */ + void arm_mat_init_q15( + arm_matrix_instance_q15 * S, + uint16_t nRows, + uint16_t nColumns, + q15_t * pData); + + + /** + * @brief Floating-point matrix initialization. + * @param[in,out] S points to an instance of the floating-point matrix structure. + * @param[in] nRows number of rows in the matrix. + * @param[in] nColumns number of columns in the matrix. + * @param[in] pData points to the matrix data array. + */ + void arm_mat_init_f32( + arm_matrix_instance_f32 * S, + uint16_t nRows, + uint16_t nColumns, + float32_t * pData); + + + + /** + * @brief Instance structure for the Q15 PID Control. + */ + typedef struct + { + q15_t A0; /**< The derived gain, A0 = Kp + Ki + Kd . */ +#if !defined (ARM_MATH_DSP) + q15_t A1; + q15_t A2; +#else + q31_t A1; /**< The derived gain A1 = -Kp - 2Kd | Kd.*/ +#endif + q15_t state[3]; /**< The state array of length 3. */ + q15_t Kp; /**< The proportional gain. */ + q15_t Ki; /**< The integral gain. */ + q15_t Kd; /**< The derivative gain. */ + } arm_pid_instance_q15; + + /** + * @brief Instance structure for the Q31 PID Control. + */ + typedef struct + { + q31_t A0; /**< The derived gain, A0 = Kp + Ki + Kd . */ + q31_t A1; /**< The derived gain, A1 = -Kp - 2Kd. */ + q31_t A2; /**< The derived gain, A2 = Kd . */ + q31_t state[3]; /**< The state array of length 3. */ + q31_t Kp; /**< The proportional gain. */ + q31_t Ki; /**< The integral gain. */ + q31_t Kd; /**< The derivative gain. */ + } arm_pid_instance_q31; + + /** + * @brief Instance structure for the floating-point PID Control. + */ + typedef struct + { + float32_t A0; /**< The derived gain, A0 = Kp + Ki + Kd . */ + float32_t A1; /**< The derived gain, A1 = -Kp - 2Kd. */ + float32_t A2; /**< The derived gain, A2 = Kd . */ + float32_t state[3]; /**< The state array of length 3. */ + float32_t Kp; /**< The proportional gain. */ + float32_t Ki; /**< The integral gain. */ + float32_t Kd; /**< The derivative gain. */ + } arm_pid_instance_f32; + + + + /** + * @brief Initialization function for the floating-point PID Control. + * @param[in,out] S points to an instance of the PID structure. + * @param[in] resetStateFlag flag to reset the state. 0 = no change in state 1 = reset the state. + */ + void arm_pid_init_f32( + arm_pid_instance_f32 * S, + int32_t resetStateFlag); + + + /** + * @brief Reset function for the floating-point PID Control. + * @param[in,out] S is an instance of the floating-point PID Control structure + */ + void arm_pid_reset_f32( + arm_pid_instance_f32 * S); + + + /** + * @brief Initialization function for the Q31 PID Control. + * @param[in,out] S points to an instance of the Q15 PID structure. + * @param[in] resetStateFlag flag to reset the state. 0 = no change in state 1 = reset the state. + */ + void arm_pid_init_q31( + arm_pid_instance_q31 * S, + int32_t resetStateFlag); + + + /** + * @brief Reset function for the Q31 PID Control. + * @param[in,out] S points to an instance of the Q31 PID Control structure + */ + + void arm_pid_reset_q31( + arm_pid_instance_q31 * S); + + + /** + * @brief Initialization function for the Q15 PID Control. + * @param[in,out] S points to an instance of the Q15 PID structure. + * @param[in] resetStateFlag flag to reset the state. 0 = no change in state 1 = reset the state. + */ + void arm_pid_init_q15( + arm_pid_instance_q15 * S, + int32_t resetStateFlag); + + + /** + * @brief Reset function for the Q15 PID Control. + * @param[in,out] S points to an instance of the q15 PID Control structure + */ + void arm_pid_reset_q15( + arm_pid_instance_q15 * S); + + + /** + * @brief Instance structure for the floating-point Linear Interpolate function. + */ + typedef struct + { + uint32_t nValues; /**< nValues */ + float32_t x1; /**< x1 */ + float32_t xSpacing; /**< xSpacing */ + float32_t *pYData; /**< pointer to the table of Y values */ + } arm_linear_interp_instance_f32; + + /** + * @brief Instance structure for the floating-point bilinear interpolation function. + */ + typedef struct + { + uint16_t numRows; /**< number of rows in the data table. */ + uint16_t numCols; /**< number of columns in the data table. */ + float32_t *pData; /**< points to the data table. */ + } arm_bilinear_interp_instance_f32; + + /** + * @brief Instance structure for the Q31 bilinear interpolation function. + */ + typedef struct + { + uint16_t numRows; /**< number of rows in the data table. */ + uint16_t numCols; /**< number of columns in the data table. */ + q31_t *pData; /**< points to the data table. */ + } arm_bilinear_interp_instance_q31; + + /** + * @brief Instance structure for the Q15 bilinear interpolation function. + */ + typedef struct + { + uint16_t numRows; /**< number of rows in the data table. */ + uint16_t numCols; /**< number of columns in the data table. */ + q15_t *pData; /**< points to the data table. */ + } arm_bilinear_interp_instance_q15; + + /** + * @brief Instance structure for the Q15 bilinear interpolation function. + */ + typedef struct + { + uint16_t numRows; /**< number of rows in the data table. */ + uint16_t numCols; /**< number of columns in the data table. */ + q7_t *pData; /**< points to the data table. */ + } arm_bilinear_interp_instance_q7; + + + /** + * @brief Q7 vector multiplication. + * @param[in] pSrcA points to the first input vector + * @param[in] pSrcB points to the second input vector + * @param[out] pDst points to the output vector + * @param[in] blockSize number of samples in each vector + */ + void arm_mult_q7( + q7_t * pSrcA, + q7_t * pSrcB, + q7_t * pDst, + uint32_t blockSize); + + + /** + * @brief Q15 vector multiplication. + * @param[in] pSrcA points to the first input vector + * @param[in] pSrcB points to the second input vector + * @param[out] pDst points to the output vector + * @param[in] blockSize number of samples in each vector + */ + void arm_mult_q15( + q15_t * pSrcA, + q15_t * pSrcB, + q15_t * pDst, + uint32_t blockSize); + + + /** + * @brief Q31 vector multiplication. + * @param[in] pSrcA points to the first input vector + * @param[in] pSrcB points to the second input vector + * @param[out] pDst points to the output vector + * @param[in] blockSize number of samples in each vector + */ + void arm_mult_q31( + q31_t * pSrcA, + q31_t * pSrcB, + q31_t * pDst, + uint32_t blockSize); + + + /** + * @brief Floating-point vector multiplication. + * @param[in] pSrcA points to the first input vector + * @param[in] pSrcB points to the second input vector + * @param[out] pDst points to the output vector + * @param[in] blockSize number of samples in each vector + */ + void arm_mult_f32( + float32_t * pSrcA, + float32_t * pSrcB, + float32_t * pDst, + uint32_t blockSize); + + + /** + * @brief Instance structure for the Q15 CFFT/CIFFT function. + */ + typedef struct + { + uint16_t fftLen; /**< length of the FFT. */ + uint8_t ifftFlag; /**< flag that selects forward (ifftFlag=0) or inverse (ifftFlag=1) transform. */ + uint8_t bitReverseFlag; /**< flag that enables (bitReverseFlag=1) or disables (bitReverseFlag=0) bit reversal of output. */ + q15_t *pTwiddle; /**< points to the Sin twiddle factor table. */ + uint16_t *pBitRevTable; /**< points to the bit reversal table. */ + uint16_t twidCoefModifier; /**< twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table. */ + uint16_t bitRevFactor; /**< bit reversal modifier that supports different size FFTs with the same bit reversal table. */ + } arm_cfft_radix2_instance_q15; + +/* Deprecated */ + arm_status arm_cfft_radix2_init_q15( + arm_cfft_radix2_instance_q15 * S, + uint16_t fftLen, + uint8_t ifftFlag, + uint8_t bitReverseFlag); + +/* Deprecated */ + void arm_cfft_radix2_q15( + const arm_cfft_radix2_instance_q15 * S, + q15_t * pSrc); + + + /** + * @brief Instance structure for the Q15 CFFT/CIFFT function. + */ + typedef struct + { + uint16_t fftLen; /**< length of the FFT. */ + uint8_t ifftFlag; /**< flag that selects forward (ifftFlag=0) or inverse (ifftFlag=1) transform. */ + uint8_t bitReverseFlag; /**< flag that enables (bitReverseFlag=1) or disables (bitReverseFlag=0) bit reversal of output. */ + q15_t *pTwiddle; /**< points to the twiddle factor table. */ + uint16_t *pBitRevTable; /**< points to the bit reversal table. */ + uint16_t twidCoefModifier; /**< twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table. */ + uint16_t bitRevFactor; /**< bit reversal modifier that supports different size FFTs with the same bit reversal table. */ + } arm_cfft_radix4_instance_q15; + +/* Deprecated */ + arm_status arm_cfft_radix4_init_q15( + arm_cfft_radix4_instance_q15 * S, + uint16_t fftLen, + uint8_t ifftFlag, + uint8_t bitReverseFlag); + +/* Deprecated */ + void arm_cfft_radix4_q15( + const arm_cfft_radix4_instance_q15 * S, + q15_t * pSrc); + + /** + * @brief Instance structure for the Radix-2 Q31 CFFT/CIFFT function. + */ + typedef struct + { + uint16_t fftLen; /**< length of the FFT. */ + uint8_t ifftFlag; /**< flag that selects forward (ifftFlag=0) or inverse (ifftFlag=1) transform. */ + uint8_t bitReverseFlag; /**< flag that enables (bitReverseFlag=1) or disables (bitReverseFlag=0) bit reversal of output. */ + q31_t *pTwiddle; /**< points to the Twiddle factor table. */ + uint16_t *pBitRevTable; /**< points to the bit reversal table. */ + uint16_t twidCoefModifier; /**< twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table. */ + uint16_t bitRevFactor; /**< bit reversal modifier that supports different size FFTs with the same bit reversal table. */ + } arm_cfft_radix2_instance_q31; + +/* Deprecated */ + arm_status arm_cfft_radix2_init_q31( + arm_cfft_radix2_instance_q31 * S, + uint16_t fftLen, + uint8_t ifftFlag, + uint8_t bitReverseFlag); + +/* Deprecated */ + void arm_cfft_radix2_q31( + const arm_cfft_radix2_instance_q31 * S, + q31_t * pSrc); + + /** + * @brief Instance structure for the Q31 CFFT/CIFFT function. + */ + typedef struct + { + uint16_t fftLen; /**< length of the FFT. */ + uint8_t ifftFlag; /**< flag that selects forward (ifftFlag=0) or inverse (ifftFlag=1) transform. */ + uint8_t bitReverseFlag; /**< flag that enables (bitReverseFlag=1) or disables (bitReverseFlag=0) bit reversal of output. */ + q31_t *pTwiddle; /**< points to the twiddle factor table. */ + uint16_t *pBitRevTable; /**< points to the bit reversal table. */ + uint16_t twidCoefModifier; /**< twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table. */ + uint16_t bitRevFactor; /**< bit reversal modifier that supports different size FFTs with the same bit reversal table. */ + } arm_cfft_radix4_instance_q31; + +/* Deprecated */ + void arm_cfft_radix4_q31( + const arm_cfft_radix4_instance_q31 * S, + q31_t * pSrc); + +/* Deprecated */ + arm_status arm_cfft_radix4_init_q31( + arm_cfft_radix4_instance_q31 * S, + uint16_t fftLen, + uint8_t ifftFlag, + uint8_t bitReverseFlag); + + /** + * @brief Instance structure for the floating-point CFFT/CIFFT function. + */ + typedef struct + { + uint16_t fftLen; /**< length of the FFT. */ + uint8_t ifftFlag; /**< flag that selects forward (ifftFlag=0) or inverse (ifftFlag=1) transform. */ + uint8_t bitReverseFlag; /**< flag that enables (bitReverseFlag=1) or disables (bitReverseFlag=0) bit reversal of output. */ + float32_t *pTwiddle; /**< points to the Twiddle factor table. */ + uint16_t *pBitRevTable; /**< points to the bit reversal table. */ + uint16_t twidCoefModifier; /**< twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table. */ + uint16_t bitRevFactor; /**< bit reversal modifier that supports different size FFTs with the same bit reversal table. */ + float32_t onebyfftLen; /**< value of 1/fftLen. */ + } arm_cfft_radix2_instance_f32; + +/* Deprecated */ + arm_status arm_cfft_radix2_init_f32( + arm_cfft_radix2_instance_f32 * S, + uint16_t fftLen, + uint8_t ifftFlag, + uint8_t bitReverseFlag); + +/* Deprecated */ + void arm_cfft_radix2_f32( + const arm_cfft_radix2_instance_f32 * S, + float32_t * pSrc); + + /** + * @brief Instance structure for the floating-point CFFT/CIFFT function. + */ + typedef struct + { + uint16_t fftLen; /**< length of the FFT. */ + uint8_t ifftFlag; /**< flag that selects forward (ifftFlag=0) or inverse (ifftFlag=1) transform. */ + uint8_t bitReverseFlag; /**< flag that enables (bitReverseFlag=1) or disables (bitReverseFlag=0) bit reversal of output. */ + float32_t *pTwiddle; /**< points to the Twiddle factor table. */ + uint16_t *pBitRevTable; /**< points to the bit reversal table. */ + uint16_t twidCoefModifier; /**< twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table. */ + uint16_t bitRevFactor; /**< bit reversal modifier that supports different size FFTs with the same bit reversal table. */ + float32_t onebyfftLen; /**< value of 1/fftLen. */ + } arm_cfft_radix4_instance_f32; + +/* Deprecated */ + arm_status arm_cfft_radix4_init_f32( + arm_cfft_radix4_instance_f32 * S, + uint16_t fftLen, + uint8_t ifftFlag, + uint8_t bitReverseFlag); + +/* Deprecated */ + void arm_cfft_radix4_f32( + const arm_cfft_radix4_instance_f32 * S, + float32_t * pSrc); + + /** + * @brief Instance structure for the fixed-point CFFT/CIFFT function. + */ + typedef struct + { + uint16_t fftLen; /**< length of the FFT. */ + const q15_t *pTwiddle; /**< points to the Twiddle factor table. */ + const uint16_t *pBitRevTable; /**< points to the bit reversal table. */ + uint16_t bitRevLength; /**< bit reversal table length. */ + } arm_cfft_instance_q15; + +void arm_cfft_q15( + const arm_cfft_instance_q15 * S, + q15_t * p1, + uint8_t ifftFlag, + uint8_t bitReverseFlag); + + /** + * @brief Instance structure for the fixed-point CFFT/CIFFT function. + */ + typedef struct + { + uint16_t fftLen; /**< length of the FFT. */ + const q31_t *pTwiddle; /**< points to the Twiddle factor table. */ + const uint16_t *pBitRevTable; /**< points to the bit reversal table. */ + uint16_t bitRevLength; /**< bit reversal table length. */ + } arm_cfft_instance_q31; + +void arm_cfft_q31( + const arm_cfft_instance_q31 * S, + q31_t * p1, + uint8_t ifftFlag, + uint8_t bitReverseFlag); + + /** + * @brief Instance structure for the floating-point CFFT/CIFFT function. + */ + typedef struct + { + uint16_t fftLen; /**< length of the FFT. */ + const float32_t *pTwiddle; /**< points to the Twiddle factor table. */ + const uint16_t *pBitRevTable; /**< points to the bit reversal table. */ + uint16_t bitRevLength; /**< bit reversal table length. */ + } arm_cfft_instance_f32; + + void arm_cfft_f32( + const arm_cfft_instance_f32 * S, + float32_t * p1, + uint8_t ifftFlag, + uint8_t bitReverseFlag); + + /** + * @brief Instance structure for the Q15 RFFT/RIFFT function. + */ + typedef struct + { + uint32_t fftLenReal; /**< length of the real FFT. */ + uint8_t ifftFlagR; /**< flag that selects forward (ifftFlagR=0) or inverse (ifftFlagR=1) transform. */ + uint8_t bitReverseFlagR; /**< flag that enables (bitReverseFlagR=1) or disables (bitReverseFlagR=0) bit reversal of output. */ + uint32_t twidCoefRModifier; /**< twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table. */ + q15_t *pTwiddleAReal; /**< points to the real twiddle factor table. */ + q15_t *pTwiddleBReal; /**< points to the imag twiddle factor table. */ + const arm_cfft_instance_q15 *pCfft; /**< points to the complex FFT instance. */ + } arm_rfft_instance_q15; + + arm_status arm_rfft_init_q15( + arm_rfft_instance_q15 * S, + uint32_t fftLenReal, + uint32_t ifftFlagR, + uint32_t bitReverseFlag); + + void arm_rfft_q15( + const arm_rfft_instance_q15 * S, + q15_t * pSrc, + q15_t * pDst); + + /** + * @brief Instance structure for the Q31 RFFT/RIFFT function. + */ + typedef struct + { + uint32_t fftLenReal; /**< length of the real FFT. */ + uint8_t ifftFlagR; /**< flag that selects forward (ifftFlagR=0) or inverse (ifftFlagR=1) transform. */ + uint8_t bitReverseFlagR; /**< flag that enables (bitReverseFlagR=1) or disables (bitReverseFlagR=0) bit reversal of output. */ + uint32_t twidCoefRModifier; /**< twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table. */ + q31_t *pTwiddleAReal; /**< points to the real twiddle factor table. */ + q31_t *pTwiddleBReal; /**< points to the imag twiddle factor table. */ + const arm_cfft_instance_q31 *pCfft; /**< points to the complex FFT instance. */ + } arm_rfft_instance_q31; + + arm_status arm_rfft_init_q31( + arm_rfft_instance_q31 * S, + uint32_t fftLenReal, + uint32_t ifftFlagR, + uint32_t bitReverseFlag); + + void arm_rfft_q31( + const arm_rfft_instance_q31 * S, + q31_t * pSrc, + q31_t * pDst); + + /** + * @brief Instance structure for the floating-point RFFT/RIFFT function. + */ + typedef struct + { + uint32_t fftLenReal; /**< length of the real FFT. */ + uint16_t fftLenBy2; /**< length of the complex FFT. */ + uint8_t ifftFlagR; /**< flag that selects forward (ifftFlagR=0) or inverse (ifftFlagR=1) transform. */ + uint8_t bitReverseFlagR; /**< flag that enables (bitReverseFlagR=1) or disables (bitReverseFlagR=0) bit reversal of output. */ + uint32_t twidCoefRModifier; /**< twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table. */ + float32_t *pTwiddleAReal; /**< points to the real twiddle factor table. */ + float32_t *pTwiddleBReal; /**< points to the imag twiddle factor table. */ + arm_cfft_radix4_instance_f32 *pCfft; /**< points to the complex FFT instance. */ + } arm_rfft_instance_f32; + + arm_status arm_rfft_init_f32( + arm_rfft_instance_f32 * S, + arm_cfft_radix4_instance_f32 * S_CFFT, + uint32_t fftLenReal, + uint32_t ifftFlagR, + uint32_t bitReverseFlag); + + void arm_rfft_f32( + const arm_rfft_instance_f32 * S, + float32_t * pSrc, + float32_t * pDst); + + /** + * @brief Instance structure for the floating-point RFFT/RIFFT function. + */ +typedef struct + { + arm_cfft_instance_f32 Sint; /**< Internal CFFT structure. */ + uint16_t fftLenRFFT; /**< length of the real sequence */ + float32_t * pTwiddleRFFT; /**< Twiddle factors real stage */ + } arm_rfft_fast_instance_f32 ; + +arm_status arm_rfft_fast_init_f32 ( + arm_rfft_fast_instance_f32 * S, + uint16_t fftLen); + +void arm_rfft_fast_f32( + arm_rfft_fast_instance_f32 * S, + float32_t * p, float32_t * pOut, + uint8_t ifftFlag); + + /** + * @brief Instance structure for the floating-point DCT4/IDCT4 function. + */ + typedef struct + { + uint16_t N; /**< length of the DCT4. */ + uint16_t Nby2; /**< half of the length of the DCT4. */ + float32_t normalize; /**< normalizing factor. */ + float32_t *pTwiddle; /**< points to the twiddle factor table. */ + float32_t *pCosFactor; /**< points to the cosFactor table. */ + arm_rfft_instance_f32 *pRfft; /**< points to the real FFT instance. */ + arm_cfft_radix4_instance_f32 *pCfft; /**< points to the complex FFT instance. */ + } arm_dct4_instance_f32; + + + /** + * @brief Initialization function for the floating-point DCT4/IDCT4. + * @param[in,out] S points to an instance of floating-point DCT4/IDCT4 structure. + * @param[in] S_RFFT points to an instance of floating-point RFFT/RIFFT structure. + * @param[in] S_CFFT points to an instance of floating-point CFFT/CIFFT structure. + * @param[in] N length of the DCT4. + * @param[in] Nby2 half of the length of the DCT4. + * @param[in] normalize normalizing factor. + * @return arm_status function returns ARM_MATH_SUCCESS if initialization is successful or ARM_MATH_ARGUMENT_ERROR if fftLenReal is not a supported transform length. + */ + arm_status arm_dct4_init_f32( + arm_dct4_instance_f32 * S, + arm_rfft_instance_f32 * S_RFFT, + arm_cfft_radix4_instance_f32 * S_CFFT, + uint16_t N, + uint16_t Nby2, + float32_t normalize); + + + /** + * @brief Processing function for the floating-point DCT4/IDCT4. + * @param[in] S points to an instance of the floating-point DCT4/IDCT4 structure. + * @param[in] pState points to state buffer. + * @param[in,out] pInlineBuffer points to the in-place input and output buffer. + */ + void arm_dct4_f32( + const arm_dct4_instance_f32 * S, + float32_t * pState, + float32_t * pInlineBuffer); + + + /** + * @brief Instance structure for the Q31 DCT4/IDCT4 function. + */ + typedef struct + { + uint16_t N; /**< length of the DCT4. */ + uint16_t Nby2; /**< half of the length of the DCT4. */ + q31_t normalize; /**< normalizing factor. */ + q31_t *pTwiddle; /**< points to the twiddle factor table. */ + q31_t *pCosFactor; /**< points to the cosFactor table. */ + arm_rfft_instance_q31 *pRfft; /**< points to the real FFT instance. */ + arm_cfft_radix4_instance_q31 *pCfft; /**< points to the complex FFT instance. */ + } arm_dct4_instance_q31; + + + /** + * @brief Initialization function for the Q31 DCT4/IDCT4. + * @param[in,out] S points to an instance of Q31 DCT4/IDCT4 structure. + * @param[in] S_RFFT points to an instance of Q31 RFFT/RIFFT structure + * @param[in] S_CFFT points to an instance of Q31 CFFT/CIFFT structure + * @param[in] N length of the DCT4. + * @param[in] Nby2 half of the length of the DCT4. + * @param[in] normalize normalizing factor. + * @return arm_status function returns ARM_MATH_SUCCESS if initialization is successful or ARM_MATH_ARGUMENT_ERROR if N is not a supported transform length. + */ + arm_status arm_dct4_init_q31( + arm_dct4_instance_q31 * S, + arm_rfft_instance_q31 * S_RFFT, + arm_cfft_radix4_instance_q31 * S_CFFT, + uint16_t N, + uint16_t Nby2, + q31_t normalize); + + + /** + * @brief Processing function for the Q31 DCT4/IDCT4. + * @param[in] S points to an instance of the Q31 DCT4 structure. + * @param[in] pState points to state buffer. + * @param[in,out] pInlineBuffer points to the in-place input and output buffer. + */ + void arm_dct4_q31( + const arm_dct4_instance_q31 * S, + q31_t * pState, + q31_t * pInlineBuffer); + + + /** + * @brief Instance structure for the Q15 DCT4/IDCT4 function. + */ + typedef struct + { + uint16_t N; /**< length of the DCT4. */ + uint16_t Nby2; /**< half of the length of the DCT4. */ + q15_t normalize; /**< normalizing factor. */ + q15_t *pTwiddle; /**< points to the twiddle factor table. */ + q15_t *pCosFactor; /**< points to the cosFactor table. */ + arm_rfft_instance_q15 *pRfft; /**< points to the real FFT instance. */ + arm_cfft_radix4_instance_q15 *pCfft; /**< points to the complex FFT instance. */ + } arm_dct4_instance_q15; + + + /** + * @brief Initialization function for the Q15 DCT4/IDCT4. + * @param[in,out] S points to an instance of Q15 DCT4/IDCT4 structure. + * @param[in] S_RFFT points to an instance of Q15 RFFT/RIFFT structure. + * @param[in] S_CFFT points to an instance of Q15 CFFT/CIFFT structure. + * @param[in] N length of the DCT4. + * @param[in] Nby2 half of the length of the DCT4. + * @param[in] normalize normalizing factor. + * @return arm_status function returns ARM_MATH_SUCCESS if initialization is successful or ARM_MATH_ARGUMENT_ERROR if N is not a supported transform length. + */ + arm_status arm_dct4_init_q15( + arm_dct4_instance_q15 * S, + arm_rfft_instance_q15 * S_RFFT, + arm_cfft_radix4_instance_q15 * S_CFFT, + uint16_t N, + uint16_t Nby2, + q15_t normalize); + + + /** + * @brief Processing function for the Q15 DCT4/IDCT4. + * @param[in] S points to an instance of the Q15 DCT4 structure. + * @param[in] pState points to state buffer. + * @param[in,out] pInlineBuffer points to the in-place input and output buffer. + */ + void arm_dct4_q15( + const arm_dct4_instance_q15 * S, + q15_t * pState, + q15_t * pInlineBuffer); + + + /** + * @brief Floating-point vector addition. + * @param[in] pSrcA points to the first input vector + * @param[in] pSrcB points to the second input vector + * @param[out] pDst points to the output vector + * @param[in] blockSize number of samples in each vector + */ + void arm_add_f32( + float32_t * pSrcA, + float32_t * pSrcB, + float32_t * pDst, + uint32_t blockSize); + + + /** + * @brief Q7 vector addition. + * @param[in] pSrcA points to the first input vector + * @param[in] pSrcB points to the second input vector + * @param[out] pDst points to the output vector + * @param[in] blockSize number of samples in each vector + */ + void arm_add_q7( + q7_t * pSrcA, + q7_t * pSrcB, + q7_t * pDst, + uint32_t blockSize); + + + /** + * @brief Q15 vector addition. + * @param[in] pSrcA points to the first input vector + * @param[in] pSrcB points to the second input vector + * @param[out] pDst points to the output vector + * @param[in] blockSize number of samples in each vector + */ + void arm_add_q15( + q15_t * pSrcA, + q15_t * pSrcB, + q15_t * pDst, + uint32_t blockSize); + + + /** + * @brief Q31 vector addition. + * @param[in] pSrcA points to the first input vector + * @param[in] pSrcB points to the second input vector + * @param[out] pDst points to the output vector + * @param[in] blockSize number of samples in each vector + */ + void arm_add_q31( + q31_t * pSrcA, + q31_t * pSrcB, + q31_t * pDst, + uint32_t blockSize); + + + /** + * @brief Floating-point vector subtraction. + * @param[in] pSrcA points to the first input vector + * @param[in] pSrcB points to the second input vector + * @param[out] pDst points to the output vector + * @param[in] blockSize number of samples in each vector + */ + void arm_sub_f32( + float32_t * pSrcA, + float32_t * pSrcB, + float32_t * pDst, + uint32_t blockSize); + + + /** + * @brief Q7 vector subtraction. + * @param[in] pSrcA points to the first input vector + * @param[in] pSrcB points to the second input vector + * @param[out] pDst points to the output vector + * @param[in] blockSize number of samples in each vector + */ + void arm_sub_q7( + q7_t * pSrcA, + q7_t * pSrcB, + q7_t * pDst, + uint32_t blockSize); + + + /** + * @brief Q15 vector subtraction. + * @param[in] pSrcA points to the first input vector + * @param[in] pSrcB points to the second input vector + * @param[out] pDst points to the output vector + * @param[in] blockSize number of samples in each vector + */ + void arm_sub_q15( + q15_t * pSrcA, + q15_t * pSrcB, + q15_t * pDst, + uint32_t blockSize); + + + /** + * @brief Q31 vector subtraction. + * @param[in] pSrcA points to the first input vector + * @param[in] pSrcB points to the second input vector + * @param[out] pDst points to the output vector + * @param[in] blockSize number of samples in each vector + */ + void arm_sub_q31( + q31_t * pSrcA, + q31_t * pSrcB, + q31_t * pDst, + uint32_t blockSize); + + + /** + * @brief Multiplies a floating-point vector by a scalar. + * @param[in] pSrc points to the input vector + * @param[in] scale scale factor to be applied + * @param[out] pDst points to the output vector + * @param[in] blockSize number of samples in the vector + */ + void arm_scale_f32( + float32_t * pSrc, + float32_t scale, + float32_t * pDst, + uint32_t blockSize); + + + /** + * @brief Multiplies a Q7 vector by a scalar. + * @param[in] pSrc points to the input vector + * @param[in] scaleFract fractional portion of the scale value + * @param[in] shift number of bits to shift the result by + * @param[out] pDst points to the output vector + * @param[in] blockSize number of samples in the vector + */ + void arm_scale_q7( + q7_t * pSrc, + q7_t scaleFract, + int8_t shift, + q7_t * pDst, + uint32_t blockSize); + + + /** + * @brief Multiplies a Q15 vector by a scalar. + * @param[in] pSrc points to the input vector + * @param[in] scaleFract fractional portion of the scale value + * @param[in] shift number of bits to shift the result by + * @param[out] pDst points to the output vector + * @param[in] blockSize number of samples in the vector + */ + void arm_scale_q15( + q15_t * pSrc, + q15_t scaleFract, + int8_t shift, + q15_t * pDst, + uint32_t blockSize); + + + /** + * @brief Multiplies a Q31 vector by a scalar. + * @param[in] pSrc points to the input vector + * @param[in] scaleFract fractional portion of the scale value + * @param[in] shift number of bits to shift the result by + * @param[out] pDst points to the output vector + * @param[in] blockSize number of samples in the vector + */ + void arm_scale_q31( + q31_t * pSrc, + q31_t scaleFract, + int8_t shift, + q31_t * pDst, + uint32_t blockSize); + + + /** + * @brief Q7 vector absolute value. + * @param[in] pSrc points to the input buffer + * @param[out] pDst points to the output buffer + * @param[in] blockSize number of samples in each vector + */ + void arm_abs_q7( + q7_t * pSrc, + q7_t * pDst, + uint32_t blockSize); + + + /** + * @brief Floating-point vector absolute value. + * @param[in] pSrc points to the input buffer + * @param[out] pDst points to the output buffer + * @param[in] blockSize number of samples in each vector + */ + void arm_abs_f32( + float32_t * pSrc, + float32_t * pDst, + uint32_t blockSize); + + + /** + * @brief Q15 vector absolute value. + * @param[in] pSrc points to the input buffer + * @param[out] pDst points to the output buffer + * @param[in] blockSize number of samples in each vector + */ + void arm_abs_q15( + q15_t * pSrc, + q15_t * pDst, + uint32_t blockSize); + + + /** + * @brief Q31 vector absolute value. + * @param[in] pSrc points to the input buffer + * @param[out] pDst points to the output buffer + * @param[in] blockSize number of samples in each vector + */ + void arm_abs_q31( + q31_t * pSrc, + q31_t * pDst, + uint32_t blockSize); + + + /** + * @brief Dot product of floating-point vectors. + * @param[in] pSrcA points to the first input vector + * @param[in] pSrcB points to the second input vector + * @param[in] blockSize number of samples in each vector + * @param[out] result output result returned here + */ + void arm_dot_prod_f32( + float32_t * pSrcA, + float32_t * pSrcB, + uint32_t blockSize, + float32_t * result); + + + /** + * @brief Dot product of Q7 vectors. + * @param[in] pSrcA points to the first input vector + * @param[in] pSrcB points to the second input vector + * @param[in] blockSize number of samples in each vector + * @param[out] result output result returned here + */ + void arm_dot_prod_q7( + q7_t * pSrcA, + q7_t * pSrcB, + uint32_t blockSize, + q31_t * result); + + + /** + * @brief Dot product of Q15 vectors. + * @param[in] pSrcA points to the first input vector + * @param[in] pSrcB points to the second input vector + * @param[in] blockSize number of samples in each vector + * @param[out] result output result returned here + */ + void arm_dot_prod_q15( + q15_t * pSrcA, + q15_t * pSrcB, + uint32_t blockSize, + q63_t * result); + + + /** + * @brief Dot product of Q31 vectors. + * @param[in] pSrcA points to the first input vector + * @param[in] pSrcB points to the second input vector + * @param[in] blockSize number of samples in each vector + * @param[out] result output result returned here + */ + void arm_dot_prod_q31( + q31_t * pSrcA, + q31_t * pSrcB, + uint32_t blockSize, + q63_t * result); + + + /** + * @brief Shifts the elements of a Q7 vector a specified number of bits. + * @param[in] pSrc points to the input vector + * @param[in] shiftBits number of bits to shift. A positive value shifts left; a negative value shifts right. + * @param[out] pDst points to the output vector + * @param[in] blockSize number of samples in the vector + */ + void arm_shift_q7( + q7_t * pSrc, + int8_t shiftBits, + q7_t * pDst, + uint32_t blockSize); + + + /** + * @brief Shifts the elements of a Q15 vector a specified number of bits. + * @param[in] pSrc points to the input vector + * @param[in] shiftBits number of bits to shift. A positive value shifts left; a negative value shifts right. + * @param[out] pDst points to the output vector + * @param[in] blockSize number of samples in the vector + */ + void arm_shift_q15( + q15_t * pSrc, + int8_t shiftBits, + q15_t * pDst, + uint32_t blockSize); + + + /** + * @brief Shifts the elements of a Q31 vector a specified number of bits. + * @param[in] pSrc points to the input vector + * @param[in] shiftBits number of bits to shift. A positive value shifts left; a negative value shifts right. + * @param[out] pDst points to the output vector + * @param[in] blockSize number of samples in the vector + */ + void arm_shift_q31( + q31_t * pSrc, + int8_t shiftBits, + q31_t * pDst, + uint32_t blockSize); + + + /** + * @brief Adds a constant offset to a floating-point vector. + * @param[in] pSrc points to the input vector + * @param[in] offset is the offset to be added + * @param[out] pDst points to the output vector + * @param[in] blockSize number of samples in the vector + */ + void arm_offset_f32( + float32_t * pSrc, + float32_t offset, + float32_t * pDst, + uint32_t blockSize); + + + /** + * @brief Adds a constant offset to a Q7 vector. + * @param[in] pSrc points to the input vector + * @param[in] offset is the offset to be added + * @param[out] pDst points to the output vector + * @param[in] blockSize number of samples in the vector + */ + void arm_offset_q7( + q7_t * pSrc, + q7_t offset, + q7_t * pDst, + uint32_t blockSize); + + + /** + * @brief Adds a constant offset to a Q15 vector. + * @param[in] pSrc points to the input vector + * @param[in] offset is the offset to be added + * @param[out] pDst points to the output vector + * @param[in] blockSize number of samples in the vector + */ + void arm_offset_q15( + q15_t * pSrc, + q15_t offset, + q15_t * pDst, + uint32_t blockSize); + + + /** + * @brief Adds a constant offset to a Q31 vector. + * @param[in] pSrc points to the input vector + * @param[in] offset is the offset to be added + * @param[out] pDst points to the output vector + * @param[in] blockSize number of samples in the vector + */ + void arm_offset_q31( + q31_t * pSrc, + q31_t offset, + q31_t * pDst, + uint32_t blockSize); + + + /** + * @brief Negates the elements of a floating-point vector. + * @param[in] pSrc points to the input vector + * @param[out] pDst points to the output vector + * @param[in] blockSize number of samples in the vector + */ + void arm_negate_f32( + float32_t * pSrc, + float32_t * pDst, + uint32_t blockSize); + + + /** + * @brief Negates the elements of a Q7 vector. + * @param[in] pSrc points to the input vector + * @param[out] pDst points to the output vector + * @param[in] blockSize number of samples in the vector + */ + void arm_negate_q7( + q7_t * pSrc, + q7_t * pDst, + uint32_t blockSize); + + + /** + * @brief Negates the elements of a Q15 vector. + * @param[in] pSrc points to the input vector + * @param[out] pDst points to the output vector + * @param[in] blockSize number of samples in the vector + */ + void arm_negate_q15( + q15_t * pSrc, + q15_t * pDst, + uint32_t blockSize); + + + /** + * @brief Negates the elements of a Q31 vector. + * @param[in] pSrc points to the input vector + * @param[out] pDst points to the output vector + * @param[in] blockSize number of samples in the vector + */ + void arm_negate_q31( + q31_t * pSrc, + q31_t * pDst, + uint32_t blockSize); + + + /** + * @brief Copies the elements of a floating-point vector. + * @param[in] pSrc input pointer + * @param[out] pDst output pointer + * @param[in] blockSize number of samples to process + */ + void arm_copy_f32( + float32_t * pSrc, + float32_t * pDst, + uint32_t blockSize); + + + /** + * @brief Copies the elements of a Q7 vector. + * @param[in] pSrc input pointer + * @param[out] pDst output pointer + * @param[in] blockSize number of samples to process + */ + void arm_copy_q7( + q7_t * pSrc, + q7_t * pDst, + uint32_t blockSize); + + + /** + * @brief Copies the elements of a Q15 vector. + * @param[in] pSrc input pointer + * @param[out] pDst output pointer + * @param[in] blockSize number of samples to process + */ + void arm_copy_q15( + q15_t * pSrc, + q15_t * pDst, + uint32_t blockSize); + + + /** + * @brief Copies the elements of a Q31 vector. + * @param[in] pSrc input pointer + * @param[out] pDst output pointer + * @param[in] blockSize number of samples to process + */ + void arm_copy_q31( + q31_t * pSrc, + q31_t * pDst, + uint32_t blockSize); + + + /** + * @brief Fills a constant value into a floating-point vector. + * @param[in] value input value to be filled + * @param[out] pDst output pointer + * @param[in] blockSize number of samples to process + */ + void arm_fill_f32( + float32_t value, + float32_t * pDst, + uint32_t blockSize); + + + /** + * @brief Fills a constant value into a Q7 vector. + * @param[in] value input value to be filled + * @param[out] pDst output pointer + * @param[in] blockSize number of samples to process + */ + void arm_fill_q7( + q7_t value, + q7_t * pDst, + uint32_t blockSize); + + + /** + * @brief Fills a constant value into a Q15 vector. + * @param[in] value input value to be filled + * @param[out] pDst output pointer + * @param[in] blockSize number of samples to process + */ + void arm_fill_q15( + q15_t value, + q15_t * pDst, + uint32_t blockSize); + + + /** + * @brief Fills a constant value into a Q31 vector. + * @param[in] value input value to be filled + * @param[out] pDst output pointer + * @param[in] blockSize number of samples to process + */ + void arm_fill_q31( + q31_t value, + q31_t * pDst, + uint32_t blockSize); + + +/** + * @brief Convolution of floating-point sequences. + * @param[in] pSrcA points to the first input sequence. + * @param[in] srcALen length of the first input sequence. + * @param[in] pSrcB points to the second input sequence. + * @param[in] srcBLen length of the second input sequence. + * @param[out] pDst points to the location where the output result is written. Length srcALen+srcBLen-1. + */ + void arm_conv_f32( + float32_t * pSrcA, + uint32_t srcALen, + float32_t * pSrcB, + uint32_t srcBLen, + float32_t * pDst); + + + /** + * @brief Convolution of Q15 sequences. + * @param[in] pSrcA points to the first input sequence. + * @param[in] srcALen length of the first input sequence. + * @param[in] pSrcB points to the second input sequence. + * @param[in] srcBLen length of the second input sequence. + * @param[out] pDst points to the block of output data Length srcALen+srcBLen-1. + * @param[in] pScratch1 points to scratch buffer of size max(srcALen, srcBLen) + 2*min(srcALen, srcBLen) - 2. + * @param[in] pScratch2 points to scratch buffer of size min(srcALen, srcBLen). + */ + void arm_conv_opt_q15( + q15_t * pSrcA, + uint32_t srcALen, + q15_t * pSrcB, + uint32_t srcBLen, + q15_t * pDst, + q15_t * pScratch1, + q15_t * pScratch2); + + +/** + * @brief Convolution of Q15 sequences. + * @param[in] pSrcA points to the first input sequence. + * @param[in] srcALen length of the first input sequence. + * @param[in] pSrcB points to the second input sequence. + * @param[in] srcBLen length of the second input sequence. + * @param[out] pDst points to the location where the output result is written. Length srcALen+srcBLen-1. + */ + void arm_conv_q15( + q15_t * pSrcA, + uint32_t srcALen, + q15_t * pSrcB, + uint32_t srcBLen, + q15_t * pDst); + + + /** + * @brief Convolution of Q15 sequences (fast version) for Cortex-M3 and Cortex-M4 + * @param[in] pSrcA points to the first input sequence. + * @param[in] srcALen length of the first input sequence. + * @param[in] pSrcB points to the second input sequence. + * @param[in] srcBLen length of the second input sequence. + * @param[out] pDst points to the block of output data Length srcALen+srcBLen-1. + */ + void arm_conv_fast_q15( + q15_t * pSrcA, + uint32_t srcALen, + q15_t * pSrcB, + uint32_t srcBLen, + q15_t * pDst); + + + /** + * @brief Convolution of Q15 sequences (fast version) for Cortex-M3 and Cortex-M4 + * @param[in] pSrcA points to the first input sequence. + * @param[in] srcALen length of the first input sequence. + * @param[in] pSrcB points to the second input sequence. + * @param[in] srcBLen length of the second input sequence. + * @param[out] pDst points to the block of output data Length srcALen+srcBLen-1. + * @param[in] pScratch1 points to scratch buffer of size max(srcALen, srcBLen) + 2*min(srcALen, srcBLen) - 2. + * @param[in] pScratch2 points to scratch buffer of size min(srcALen, srcBLen). + */ + void arm_conv_fast_opt_q15( + q15_t * pSrcA, + uint32_t srcALen, + q15_t * pSrcB, + uint32_t srcBLen, + q15_t * pDst, + q15_t * pScratch1, + q15_t * pScratch2); + + + /** + * @brief Convolution of Q31 sequences. + * @param[in] pSrcA points to the first input sequence. + * @param[in] srcALen length of the first input sequence. + * @param[in] pSrcB points to the second input sequence. + * @param[in] srcBLen length of the second input sequence. + * @param[out] pDst points to the block of output data Length srcALen+srcBLen-1. + */ + void arm_conv_q31( + q31_t * pSrcA, + uint32_t srcALen, + q31_t * pSrcB, + uint32_t srcBLen, + q31_t * pDst); + + + /** + * @brief Convolution of Q31 sequences (fast version) for Cortex-M3 and Cortex-M4 + * @param[in] pSrcA points to the first input sequence. + * @param[in] srcALen length of the first input sequence. + * @param[in] pSrcB points to the second input sequence. + * @param[in] srcBLen length of the second input sequence. + * @param[out] pDst points to the block of output data Length srcALen+srcBLen-1. + */ + void arm_conv_fast_q31( + q31_t * pSrcA, + uint32_t srcALen, + q31_t * pSrcB, + uint32_t srcBLen, + q31_t * pDst); + + + /** + * @brief Convolution of Q7 sequences. + * @param[in] pSrcA points to the first input sequence. + * @param[in] srcALen length of the first input sequence. + * @param[in] pSrcB points to the second input sequence. + * @param[in] srcBLen length of the second input sequence. + * @param[out] pDst points to the block of output data Length srcALen+srcBLen-1. + * @param[in] pScratch1 points to scratch buffer(of type q15_t) of size max(srcALen, srcBLen) + 2*min(srcALen, srcBLen) - 2. + * @param[in] pScratch2 points to scratch buffer (of type q15_t) of size min(srcALen, srcBLen). + */ + void arm_conv_opt_q7( + q7_t * pSrcA, + uint32_t srcALen, + q7_t * pSrcB, + uint32_t srcBLen, + q7_t * pDst, + q15_t * pScratch1, + q15_t * pScratch2); + + + /** + * @brief Convolution of Q7 sequences. + * @param[in] pSrcA points to the first input sequence. + * @param[in] srcALen length of the first input sequence. + * @param[in] pSrcB points to the second input sequence. + * @param[in] srcBLen length of the second input sequence. + * @param[out] pDst points to the block of output data Length srcALen+srcBLen-1. + */ + void arm_conv_q7( + q7_t * pSrcA, + uint32_t srcALen, + q7_t * pSrcB, + uint32_t srcBLen, + q7_t * pDst); + + + /** + * @brief Partial convolution of floating-point sequences. + * @param[in] pSrcA points to the first input sequence. + * @param[in] srcALen length of the first input sequence. + * @param[in] pSrcB points to the second input sequence. + * @param[in] srcBLen length of the second input sequence. + * @param[out] pDst points to the block of output data + * @param[in] firstIndex is the first output sample to start with. + * @param[in] numPoints is the number of output points to be computed. + * @return Returns either ARM_MATH_SUCCESS if the function completed correctly or ARM_MATH_ARGUMENT_ERROR if the requested subset is not in the range [0 srcALen+srcBLen-2]. + */ + arm_status arm_conv_partial_f32( + float32_t * pSrcA, + uint32_t srcALen, + float32_t * pSrcB, + uint32_t srcBLen, + float32_t * pDst, + uint32_t firstIndex, + uint32_t numPoints); + + + /** + * @brief Partial convolution of Q15 sequences. + * @param[in] pSrcA points to the first input sequence. + * @param[in] srcALen length of the first input sequence. + * @param[in] pSrcB points to the second input sequence. + * @param[in] srcBLen length of the second input sequence. + * @param[out] pDst points to the block of output data + * @param[in] firstIndex is the first output sample to start with. + * @param[in] numPoints is the number of output points to be computed. + * @param[in] pScratch1 points to scratch buffer of size max(srcALen, srcBLen) + 2*min(srcALen, srcBLen) - 2. + * @param[in] pScratch2 points to scratch buffer of size min(srcALen, srcBLen). + * @return Returns either ARM_MATH_SUCCESS if the function completed correctly or ARM_MATH_ARGUMENT_ERROR if the requested subset is not in the range [0 srcALen+srcBLen-2]. + */ + arm_status arm_conv_partial_opt_q15( + q15_t * pSrcA, + uint32_t srcALen, + q15_t * pSrcB, + uint32_t srcBLen, + q15_t * pDst, + uint32_t firstIndex, + uint32_t numPoints, + q15_t * pScratch1, + q15_t * pScratch2); + + + /** + * @brief Partial convolution of Q15 sequences. + * @param[in] pSrcA points to the first input sequence. + * @param[in] srcALen length of the first input sequence. + * @param[in] pSrcB points to the second input sequence. + * @param[in] srcBLen length of the second input sequence. + * @param[out] pDst points to the block of output data + * @param[in] firstIndex is the first output sample to start with. + * @param[in] numPoints is the number of output points to be computed. + * @return Returns either ARM_MATH_SUCCESS if the function completed correctly or ARM_MATH_ARGUMENT_ERROR if the requested subset is not in the range [0 srcALen+srcBLen-2]. + */ + arm_status arm_conv_partial_q15( + q15_t * pSrcA, + uint32_t srcALen, + q15_t * pSrcB, + uint32_t srcBLen, + q15_t * pDst, + uint32_t firstIndex, + uint32_t numPoints); + + + /** + * @brief Partial convolution of Q15 sequences (fast version) for Cortex-M3 and Cortex-M4 + * @param[in] pSrcA points to the first input sequence. + * @param[in] srcALen length of the first input sequence. + * @param[in] pSrcB points to the second input sequence. + * @param[in] srcBLen length of the second input sequence. + * @param[out] pDst points to the block of output data + * @param[in] firstIndex is the first output sample to start with. + * @param[in] numPoints is the number of output points to be computed. + * @return Returns either ARM_MATH_SUCCESS if the function completed correctly or ARM_MATH_ARGUMENT_ERROR if the requested subset is not in the range [0 srcALen+srcBLen-2]. + */ + arm_status arm_conv_partial_fast_q15( + q15_t * pSrcA, + uint32_t srcALen, + q15_t * pSrcB, + uint32_t srcBLen, + q15_t * pDst, + uint32_t firstIndex, + uint32_t numPoints); + + + /** + * @brief Partial convolution of Q15 sequences (fast version) for Cortex-M3 and Cortex-M4 + * @param[in] pSrcA points to the first input sequence. + * @param[in] srcALen length of the first input sequence. + * @param[in] pSrcB points to the second input sequence. + * @param[in] srcBLen length of the second input sequence. + * @param[out] pDst points to the block of output data + * @param[in] firstIndex is the first output sample to start with. + * @param[in] numPoints is the number of output points to be computed. + * @param[in] pScratch1 points to scratch buffer of size max(srcALen, srcBLen) + 2*min(srcALen, srcBLen) - 2. + * @param[in] pScratch2 points to scratch buffer of size min(srcALen, srcBLen). + * @return Returns either ARM_MATH_SUCCESS if the function completed correctly or ARM_MATH_ARGUMENT_ERROR if the requested subset is not in the range [0 srcALen+srcBLen-2]. + */ + arm_status arm_conv_partial_fast_opt_q15( + q15_t * pSrcA, + uint32_t srcALen, + q15_t * pSrcB, + uint32_t srcBLen, + q15_t * pDst, + uint32_t firstIndex, + uint32_t numPoints, + q15_t * pScratch1, + q15_t * pScratch2); + + + /** + * @brief Partial convolution of Q31 sequences. + * @param[in] pSrcA points to the first input sequence. + * @param[in] srcALen length of the first input sequence. + * @param[in] pSrcB points to the second input sequence. + * @param[in] srcBLen length of the second input sequence. + * @param[out] pDst points to the block of output data + * @param[in] firstIndex is the first output sample to start with. + * @param[in] numPoints is the number of output points to be computed. + * @return Returns either ARM_MATH_SUCCESS if the function completed correctly or ARM_MATH_ARGUMENT_ERROR if the requested subset is not in the range [0 srcALen+srcBLen-2]. + */ + arm_status arm_conv_partial_q31( + q31_t * pSrcA, + uint32_t srcALen, + q31_t * pSrcB, + uint32_t srcBLen, + q31_t * pDst, + uint32_t firstIndex, + uint32_t numPoints); + + + /** + * @brief Partial convolution of Q31 sequences (fast version) for Cortex-M3 and Cortex-M4 + * @param[in] pSrcA points to the first input sequence. + * @param[in] srcALen length of the first input sequence. + * @param[in] pSrcB points to the second input sequence. + * @param[in] srcBLen length of the second input sequence. + * @param[out] pDst points to the block of output data + * @param[in] firstIndex is the first output sample to start with. + * @param[in] numPoints is the number of output points to be computed. + * @return Returns either ARM_MATH_SUCCESS if the function completed correctly or ARM_MATH_ARGUMENT_ERROR if the requested subset is not in the range [0 srcALen+srcBLen-2]. + */ + arm_status arm_conv_partial_fast_q31( + q31_t * pSrcA, + uint32_t srcALen, + q31_t * pSrcB, + uint32_t srcBLen, + q31_t * pDst, + uint32_t firstIndex, + uint32_t numPoints); + + + /** + * @brief Partial convolution of Q7 sequences + * @param[in] pSrcA points to the first input sequence. + * @param[in] srcALen length of the first input sequence. + * @param[in] pSrcB points to the second input sequence. + * @param[in] srcBLen length of the second input sequence. + * @param[out] pDst points to the block of output data + * @param[in] firstIndex is the first output sample to start with. + * @param[in] numPoints is the number of output points to be computed. + * @param[in] pScratch1 points to scratch buffer(of type q15_t) of size max(srcALen, srcBLen) + 2*min(srcALen, srcBLen) - 2. + * @param[in] pScratch2 points to scratch buffer (of type q15_t) of size min(srcALen, srcBLen). + * @return Returns either ARM_MATH_SUCCESS if the function completed correctly or ARM_MATH_ARGUMENT_ERROR if the requested subset is not in the range [0 srcALen+srcBLen-2]. + */ + arm_status arm_conv_partial_opt_q7( + q7_t * pSrcA, + uint32_t srcALen, + q7_t * pSrcB, + uint32_t srcBLen, + q7_t * pDst, + uint32_t firstIndex, + uint32_t numPoints, + q15_t * pScratch1, + q15_t * pScratch2); + + +/** + * @brief Partial convolution of Q7 sequences. + * @param[in] pSrcA points to the first input sequence. + * @param[in] srcALen length of the first input sequence. + * @param[in] pSrcB points to the second input sequence. + * @param[in] srcBLen length of the second input sequence. + * @param[out] pDst points to the block of output data + * @param[in] firstIndex is the first output sample to start with. + * @param[in] numPoints is the number of output points to be computed. + * @return Returns either ARM_MATH_SUCCESS if the function completed correctly or ARM_MATH_ARGUMENT_ERROR if the requested subset is not in the range [0 srcALen+srcBLen-2]. + */ + arm_status arm_conv_partial_q7( + q7_t * pSrcA, + uint32_t srcALen, + q7_t * pSrcB, + uint32_t srcBLen, + q7_t * pDst, + uint32_t firstIndex, + uint32_t numPoints); + + + /** + * @brief Instance structure for the Q15 FIR decimator. + */ + typedef struct + { + uint8_t M; /**< decimation factor. */ + uint16_t numTaps; /**< number of coefficients in the filter. */ + q15_t *pCoeffs; /**< points to the coefficient array. The array is of length numTaps.*/ + q15_t *pState; /**< points to the state variable array. The array is of length numTaps+blockSize-1. */ + } arm_fir_decimate_instance_q15; + + /** + * @brief Instance structure for the Q31 FIR decimator. + */ + typedef struct + { + uint8_t M; /**< decimation factor. */ + uint16_t numTaps; /**< number of coefficients in the filter. */ + q31_t *pCoeffs; /**< points to the coefficient array. The array is of length numTaps.*/ + q31_t *pState; /**< points to the state variable array. The array is of length numTaps+blockSize-1. */ + } arm_fir_decimate_instance_q31; + + /** + * @brief Instance structure for the floating-point FIR decimator. + */ + typedef struct + { + uint8_t M; /**< decimation factor. */ + uint16_t numTaps; /**< number of coefficients in the filter. */ + float32_t *pCoeffs; /**< points to the coefficient array. The array is of length numTaps.*/ + float32_t *pState; /**< points to the state variable array. The array is of length numTaps+blockSize-1. */ + } arm_fir_decimate_instance_f32; + + + /** + * @brief Processing function for the floating-point FIR decimator. + * @param[in] S points to an instance of the floating-point FIR decimator structure. + * @param[in] pSrc points to the block of input data. + * @param[out] pDst points to the block of output data + * @param[in] blockSize number of input samples to process per call. + */ + void arm_fir_decimate_f32( + const arm_fir_decimate_instance_f32 * S, + float32_t * pSrc, + float32_t * pDst, + uint32_t blockSize); + + + /** + * @brief Initialization function for the floating-point FIR decimator. + * @param[in,out] S points to an instance of the floating-point FIR decimator structure. + * @param[in] numTaps number of coefficients in the filter. + * @param[in] M decimation factor. + * @param[in] pCoeffs points to the filter coefficients. + * @param[in] pState points to the state buffer. + * @param[in] blockSize number of input samples to process per call. + * @return The function returns ARM_MATH_SUCCESS if initialization is successful or ARM_MATH_LENGTH_ERROR if + * blockSize is not a multiple of M. + */ + arm_status arm_fir_decimate_init_f32( + arm_fir_decimate_instance_f32 * S, + uint16_t numTaps, + uint8_t M, + float32_t * pCoeffs, + float32_t * pState, + uint32_t blockSize); + + + /** + * @brief Processing function for the Q15 FIR decimator. + * @param[in] S points to an instance of the Q15 FIR decimator structure. + * @param[in] pSrc points to the block of input data. + * @param[out] pDst points to the block of output data + * @param[in] blockSize number of input samples to process per call. + */ + void arm_fir_decimate_q15( + const arm_fir_decimate_instance_q15 * S, + q15_t * pSrc, + q15_t * pDst, + uint32_t blockSize); + + + /** + * @brief Processing function for the Q15 FIR decimator (fast variant) for Cortex-M3 and Cortex-M4. + * @param[in] S points to an instance of the Q15 FIR decimator structure. + * @param[in] pSrc points to the block of input data. + * @param[out] pDst points to the block of output data + * @param[in] blockSize number of input samples to process per call. + */ + void arm_fir_decimate_fast_q15( + const arm_fir_decimate_instance_q15 * S, + q15_t * pSrc, + q15_t * pDst, + uint32_t blockSize); + + + /** + * @brief Initialization function for the Q15 FIR decimator. + * @param[in,out] S points to an instance of the Q15 FIR decimator structure. + * @param[in] numTaps number of coefficients in the filter. + * @param[in] M decimation factor. + * @param[in] pCoeffs points to the filter coefficients. + * @param[in] pState points to the state buffer. + * @param[in] blockSize number of input samples to process per call. + * @return The function returns ARM_MATH_SUCCESS if initialization is successful or ARM_MATH_LENGTH_ERROR if + * blockSize is not a multiple of M. + */ + arm_status arm_fir_decimate_init_q15( + arm_fir_decimate_instance_q15 * S, + uint16_t numTaps, + uint8_t M, + q15_t * pCoeffs, + q15_t * pState, + uint32_t blockSize); + + + /** + * @brief Processing function for the Q31 FIR decimator. + * @param[in] S points to an instance of the Q31 FIR decimator structure. + * @param[in] pSrc points to the block of input data. + * @param[out] pDst points to the block of output data + * @param[in] blockSize number of input samples to process per call. + */ + void arm_fir_decimate_q31( + const arm_fir_decimate_instance_q31 * S, + q31_t * pSrc, + q31_t * pDst, + uint32_t blockSize); + + /** + * @brief Processing function for the Q31 FIR decimator (fast variant) for Cortex-M3 and Cortex-M4. + * @param[in] S points to an instance of the Q31 FIR decimator structure. + * @param[in] pSrc points to the block of input data. + * @param[out] pDst points to the block of output data + * @param[in] blockSize number of input samples to process per call. + */ + void arm_fir_decimate_fast_q31( + arm_fir_decimate_instance_q31 * S, + q31_t * pSrc, + q31_t * pDst, + uint32_t blockSize); + + + /** + * @brief Initialization function for the Q31 FIR decimator. + * @param[in,out] S points to an instance of the Q31 FIR decimator structure. + * @param[in] numTaps number of coefficients in the filter. + * @param[in] M decimation factor. + * @param[in] pCoeffs points to the filter coefficients. + * @param[in] pState points to the state buffer. + * @param[in] blockSize number of input samples to process per call. + * @return The function returns ARM_MATH_SUCCESS if initialization is successful or ARM_MATH_LENGTH_ERROR if + * blockSize is not a multiple of M. + */ + arm_status arm_fir_decimate_init_q31( + arm_fir_decimate_instance_q31 * S, + uint16_t numTaps, + uint8_t M, + q31_t * pCoeffs, + q31_t * pState, + uint32_t blockSize); + + + /** + * @brief Instance structure for the Q15 FIR interpolator. + */ + typedef struct + { + uint8_t L; /**< upsample factor. */ + uint16_t phaseLength; /**< length of each polyphase filter component. */ + q15_t *pCoeffs; /**< points to the coefficient array. The array is of length L*phaseLength. */ + q15_t *pState; /**< points to the state variable array. The array is of length blockSize+phaseLength-1. */ + } arm_fir_interpolate_instance_q15; + + /** + * @brief Instance structure for the Q31 FIR interpolator. + */ + typedef struct + { + uint8_t L; /**< upsample factor. */ + uint16_t phaseLength; /**< length of each polyphase filter component. */ + q31_t *pCoeffs; /**< points to the coefficient array. The array is of length L*phaseLength. */ + q31_t *pState; /**< points to the state variable array. The array is of length blockSize+phaseLength-1. */ + } arm_fir_interpolate_instance_q31; + + /** + * @brief Instance structure for the floating-point FIR interpolator. + */ + typedef struct + { + uint8_t L; /**< upsample factor. */ + uint16_t phaseLength; /**< length of each polyphase filter component. */ + float32_t *pCoeffs; /**< points to the coefficient array. The array is of length L*phaseLength. */ + float32_t *pState; /**< points to the state variable array. The array is of length phaseLength+numTaps-1. */ + } arm_fir_interpolate_instance_f32; + + + /** + * @brief Processing function for the Q15 FIR interpolator. + * @param[in] S points to an instance of the Q15 FIR interpolator structure. + * @param[in] pSrc points to the block of input data. + * @param[out] pDst points to the block of output data. + * @param[in] blockSize number of input samples to process per call. + */ + void arm_fir_interpolate_q15( + const arm_fir_interpolate_instance_q15 * S, + q15_t * pSrc, + q15_t * pDst, + uint32_t blockSize); + + + /** + * @brief Initialization function for the Q15 FIR interpolator. + * @param[in,out] S points to an instance of the Q15 FIR interpolator structure. + * @param[in] L upsample factor. + * @param[in] numTaps number of filter coefficients in the filter. + * @param[in] pCoeffs points to the filter coefficient buffer. + * @param[in] pState points to the state buffer. + * @param[in] blockSize number of input samples to process per call. + * @return The function returns ARM_MATH_SUCCESS if initialization is successful or ARM_MATH_LENGTH_ERROR if + * the filter length numTaps is not a multiple of the interpolation factor L. + */ + arm_status arm_fir_interpolate_init_q15( + arm_fir_interpolate_instance_q15 * S, + uint8_t L, + uint16_t numTaps, + q15_t * pCoeffs, + q15_t * pState, + uint32_t blockSize); + + + /** + * @brief Processing function for the Q31 FIR interpolator. + * @param[in] S points to an instance of the Q15 FIR interpolator structure. + * @param[in] pSrc points to the block of input data. + * @param[out] pDst points to the block of output data. + * @param[in] blockSize number of input samples to process per call. + */ + void arm_fir_interpolate_q31( + const arm_fir_interpolate_instance_q31 * S, + q31_t * pSrc, + q31_t * pDst, + uint32_t blockSize); + + + /** + * @brief Initialization function for the Q31 FIR interpolator. + * @param[in,out] S points to an instance of the Q31 FIR interpolator structure. + * @param[in] L upsample factor. + * @param[in] numTaps number of filter coefficients in the filter. + * @param[in] pCoeffs points to the filter coefficient buffer. + * @param[in] pState points to the state buffer. + * @param[in] blockSize number of input samples to process per call. + * @return The function returns ARM_MATH_SUCCESS if initialization is successful or ARM_MATH_LENGTH_ERROR if + * the filter length numTaps is not a multiple of the interpolation factor L. + */ + arm_status arm_fir_interpolate_init_q31( + arm_fir_interpolate_instance_q31 * S, + uint8_t L, + uint16_t numTaps, + q31_t * pCoeffs, + q31_t * pState, + uint32_t blockSize); + + + /** + * @brief Processing function for the floating-point FIR interpolator. + * @param[in] S points to an instance of the floating-point FIR interpolator structure. + * @param[in] pSrc points to the block of input data. + * @param[out] pDst points to the block of output data. + * @param[in] blockSize number of input samples to process per call. + */ + void arm_fir_interpolate_f32( + const arm_fir_interpolate_instance_f32 * S, + float32_t * pSrc, + float32_t * pDst, + uint32_t blockSize); + + + /** + * @brief Initialization function for the floating-point FIR interpolator. + * @param[in,out] S points to an instance of the floating-point FIR interpolator structure. + * @param[in] L upsample factor. + * @param[in] numTaps number of filter coefficients in the filter. + * @param[in] pCoeffs points to the filter coefficient buffer. + * @param[in] pState points to the state buffer. + * @param[in] blockSize number of input samples to process per call. + * @return The function returns ARM_MATH_SUCCESS if initialization is successful or ARM_MATH_LENGTH_ERROR if + * the filter length numTaps is not a multiple of the interpolation factor L. + */ + arm_status arm_fir_interpolate_init_f32( + arm_fir_interpolate_instance_f32 * S, + uint8_t L, + uint16_t numTaps, + float32_t * pCoeffs, + float32_t * pState, + uint32_t blockSize); + + + /** + * @brief Instance structure for the high precision Q31 Biquad cascade filter. + */ + typedef struct + { + uint8_t numStages; /**< number of 2nd order stages in the filter. Overall order is 2*numStages. */ + q63_t *pState; /**< points to the array of state coefficients. The array is of length 4*numStages. */ + q31_t *pCoeffs; /**< points to the array of coefficients. The array is of length 5*numStages. */ + uint8_t postShift; /**< additional shift, in bits, applied to each output sample. */ + } arm_biquad_cas_df1_32x64_ins_q31; + + + /** + * @param[in] S points to an instance of the high precision Q31 Biquad cascade filter structure. + * @param[in] pSrc points to the block of input data. + * @param[out] pDst points to the block of output data + * @param[in] blockSize number of samples to process. + */ + void arm_biquad_cas_df1_32x64_q31( + const arm_biquad_cas_df1_32x64_ins_q31 * S, + q31_t * pSrc, + q31_t * pDst, + uint32_t blockSize); + + + /** + * @param[in,out] S points to an instance of the high precision Q31 Biquad cascade filter structure. + * @param[in] numStages number of 2nd order stages in the filter. + * @param[in] pCoeffs points to the filter coefficients. + * @param[in] pState points to the state buffer. + * @param[in] postShift shift to be applied to the output. Varies according to the coefficients format + */ + void arm_biquad_cas_df1_32x64_init_q31( + arm_biquad_cas_df1_32x64_ins_q31 * S, + uint8_t numStages, + q31_t * pCoeffs, + q63_t * pState, + uint8_t postShift); + + + /** + * @brief Instance structure for the floating-point transposed direct form II Biquad cascade filter. + */ + typedef struct + { + uint8_t numStages; /**< number of 2nd order stages in the filter. Overall order is 2*numStages. */ + float32_t *pState; /**< points to the array of state coefficients. The array is of length 2*numStages. */ + float32_t *pCoeffs; /**< points to the array of coefficients. The array is of length 5*numStages. */ + } arm_biquad_cascade_df2T_instance_f32; + + /** + * @brief Instance structure for the floating-point transposed direct form II Biquad cascade filter. + */ + typedef struct + { + uint8_t numStages; /**< number of 2nd order stages in the filter. Overall order is 2*numStages. */ + float32_t *pState; /**< points to the array of state coefficients. The array is of length 4*numStages. */ + float32_t *pCoeffs; /**< points to the array of coefficients. The array is of length 5*numStages. */ + } arm_biquad_cascade_stereo_df2T_instance_f32; + + /** + * @brief Instance structure for the floating-point transposed direct form II Biquad cascade filter. + */ + typedef struct + { + uint8_t numStages; /**< number of 2nd order stages in the filter. Overall order is 2*numStages. */ + float64_t *pState; /**< points to the array of state coefficients. The array is of length 2*numStages. */ + float64_t *pCoeffs; /**< points to the array of coefficients. The array is of length 5*numStages. */ + } arm_biquad_cascade_df2T_instance_f64; + + + /** + * @brief Processing function for the floating-point transposed direct form II Biquad cascade filter. + * @param[in] S points to an instance of the filter data structure. + * @param[in] pSrc points to the block of input data. + * @param[out] pDst points to the block of output data + * @param[in] blockSize number of samples to process. + */ + void arm_biquad_cascade_df2T_f32( + const arm_biquad_cascade_df2T_instance_f32 * S, + float32_t * pSrc, + float32_t * pDst, + uint32_t blockSize); + + + /** + * @brief Processing function for the floating-point transposed direct form II Biquad cascade filter. 2 channels + * @param[in] S points to an instance of the filter data structure. + * @param[in] pSrc points to the block of input data. + * @param[out] pDst points to the block of output data + * @param[in] blockSize number of samples to process. + */ + void arm_biquad_cascade_stereo_df2T_f32( + const arm_biquad_cascade_stereo_df2T_instance_f32 * S, + float32_t * pSrc, + float32_t * pDst, + uint32_t blockSize); + + + /** + * @brief Processing function for the floating-point transposed direct form II Biquad cascade filter. + * @param[in] S points to an instance of the filter data structure. + * @param[in] pSrc points to the block of input data. + * @param[out] pDst points to the block of output data + * @param[in] blockSize number of samples to process. + */ + void arm_biquad_cascade_df2T_f64( + const arm_biquad_cascade_df2T_instance_f64 * S, + float64_t * pSrc, + float64_t * pDst, + uint32_t blockSize); + + + /** + * @brief Initialization function for the floating-point transposed direct form II Biquad cascade filter. + * @param[in,out] S points to an instance of the filter data structure. + * @param[in] numStages number of 2nd order stages in the filter. + * @param[in] pCoeffs points to the filter coefficients. + * @param[in] pState points to the state buffer. + */ + void arm_biquad_cascade_df2T_init_f32( + arm_biquad_cascade_df2T_instance_f32 * S, + uint8_t numStages, + float32_t * pCoeffs, + float32_t * pState); + + + /** + * @brief Initialization function for the floating-point transposed direct form II Biquad cascade filter. + * @param[in,out] S points to an instance of the filter data structure. + * @param[in] numStages number of 2nd order stages in the filter. + * @param[in] pCoeffs points to the filter coefficients. + * @param[in] pState points to the state buffer. + */ + void arm_biquad_cascade_stereo_df2T_init_f32( + arm_biquad_cascade_stereo_df2T_instance_f32 * S, + uint8_t numStages, + float32_t * pCoeffs, + float32_t * pState); + + + /** + * @brief Initialization function for the floating-point transposed direct form II Biquad cascade filter. + * @param[in,out] S points to an instance of the filter data structure. + * @param[in] numStages number of 2nd order stages in the filter. + * @param[in] pCoeffs points to the filter coefficients. + * @param[in] pState points to the state buffer. + */ + void arm_biquad_cascade_df2T_init_f64( + arm_biquad_cascade_df2T_instance_f64 * S, + uint8_t numStages, + float64_t * pCoeffs, + float64_t * pState); + + + /** + * @brief Instance structure for the Q15 FIR lattice filter. + */ + typedef struct + { + uint16_t numStages; /**< number of filter stages. */ + q15_t *pState; /**< points to the state variable array. The array is of length numStages. */ + q15_t *pCoeffs; /**< points to the coefficient array. The array is of length numStages. */ + } arm_fir_lattice_instance_q15; + + /** + * @brief Instance structure for the Q31 FIR lattice filter. + */ + typedef struct + { + uint16_t numStages; /**< number of filter stages. */ + q31_t *pState; /**< points to the state variable array. The array is of length numStages. */ + q31_t *pCoeffs; /**< points to the coefficient array. The array is of length numStages. */ + } arm_fir_lattice_instance_q31; + + /** + * @brief Instance structure for the floating-point FIR lattice filter. + */ + typedef struct + { + uint16_t numStages; /**< number of filter stages. */ + float32_t *pState; /**< points to the state variable array. The array is of length numStages. */ + float32_t *pCoeffs; /**< points to the coefficient array. The array is of length numStages. */ + } arm_fir_lattice_instance_f32; + + + /** + * @brief Initialization function for the Q15 FIR lattice filter. + * @param[in] S points to an instance of the Q15 FIR lattice structure. + * @param[in] numStages number of filter stages. + * @param[in] pCoeffs points to the coefficient buffer. The array is of length numStages. + * @param[in] pState points to the state buffer. The array is of length numStages. + */ + void arm_fir_lattice_init_q15( + arm_fir_lattice_instance_q15 * S, + uint16_t numStages, + q15_t * pCoeffs, + q15_t * pState); + + + /** + * @brief Processing function for the Q15 FIR lattice filter. + * @param[in] S points to an instance of the Q15 FIR lattice structure. + * @param[in] pSrc points to the block of input data. + * @param[out] pDst points to the block of output data. + * @param[in] blockSize number of samples to process. + */ + void arm_fir_lattice_q15( + const arm_fir_lattice_instance_q15 * S, + q15_t * pSrc, + q15_t * pDst, + uint32_t blockSize); + + + /** + * @brief Initialization function for the Q31 FIR lattice filter. + * @param[in] S points to an instance of the Q31 FIR lattice structure. + * @param[in] numStages number of filter stages. + * @param[in] pCoeffs points to the coefficient buffer. The array is of length numStages. + * @param[in] pState points to the state buffer. The array is of length numStages. + */ + void arm_fir_lattice_init_q31( + arm_fir_lattice_instance_q31 * S, + uint16_t numStages, + q31_t * pCoeffs, + q31_t * pState); + + + /** + * @brief Processing function for the Q31 FIR lattice filter. + * @param[in] S points to an instance of the Q31 FIR lattice structure. + * @param[in] pSrc points to the block of input data. + * @param[out] pDst points to the block of output data + * @param[in] blockSize number of samples to process. + */ + void arm_fir_lattice_q31( + const arm_fir_lattice_instance_q31 * S, + q31_t * pSrc, + q31_t * pDst, + uint32_t blockSize); + + +/** + * @brief Initialization function for the floating-point FIR lattice filter. + * @param[in] S points to an instance of the floating-point FIR lattice structure. + * @param[in] numStages number of filter stages. + * @param[in] pCoeffs points to the coefficient buffer. The array is of length numStages. + * @param[in] pState points to the state buffer. The array is of length numStages. + */ + void arm_fir_lattice_init_f32( + arm_fir_lattice_instance_f32 * S, + uint16_t numStages, + float32_t * pCoeffs, + float32_t * pState); + + + /** + * @brief Processing function for the floating-point FIR lattice filter. + * @param[in] S points to an instance of the floating-point FIR lattice structure. + * @param[in] pSrc points to the block of input data. + * @param[out] pDst points to the block of output data + * @param[in] blockSize number of samples to process. + */ + void arm_fir_lattice_f32( + const arm_fir_lattice_instance_f32 * S, + float32_t * pSrc, + float32_t * pDst, + uint32_t blockSize); + + + /** + * @brief Instance structure for the Q15 IIR lattice filter. + */ + typedef struct + { + uint16_t numStages; /**< number of stages in the filter. */ + q15_t *pState; /**< points to the state variable array. The array is of length numStages+blockSize. */ + q15_t *pkCoeffs; /**< points to the reflection coefficient array. The array is of length numStages. */ + q15_t *pvCoeffs; /**< points to the ladder coefficient array. The array is of length numStages+1. */ + } arm_iir_lattice_instance_q15; + + /** + * @brief Instance structure for the Q31 IIR lattice filter. + */ + typedef struct + { + uint16_t numStages; /**< number of stages in the filter. */ + q31_t *pState; /**< points to the state variable array. The array is of length numStages+blockSize. */ + q31_t *pkCoeffs; /**< points to the reflection coefficient array. The array is of length numStages. */ + q31_t *pvCoeffs; /**< points to the ladder coefficient array. The array is of length numStages+1. */ + } arm_iir_lattice_instance_q31; + + /** + * @brief Instance structure for the floating-point IIR lattice filter. + */ + typedef struct + { + uint16_t numStages; /**< number of stages in the filter. */ + float32_t *pState; /**< points to the state variable array. The array is of length numStages+blockSize. */ + float32_t *pkCoeffs; /**< points to the reflection coefficient array. The array is of length numStages. */ + float32_t *pvCoeffs; /**< points to the ladder coefficient array. The array is of length numStages+1. */ + } arm_iir_lattice_instance_f32; + + + /** + * @brief Processing function for the floating-point IIR lattice filter. + * @param[in] S points to an instance of the floating-point IIR lattice structure. + * @param[in] pSrc points to the block of input data. + * @param[out] pDst points to the block of output data. + * @param[in] blockSize number of samples to process. + */ + void arm_iir_lattice_f32( + const arm_iir_lattice_instance_f32 * S, + float32_t * pSrc, + float32_t * pDst, + uint32_t blockSize); + + + /** + * @brief Initialization function for the floating-point IIR lattice filter. + * @param[in] S points to an instance of the floating-point IIR lattice structure. + * @param[in] numStages number of stages in the filter. + * @param[in] pkCoeffs points to the reflection coefficient buffer. The array is of length numStages. + * @param[in] pvCoeffs points to the ladder coefficient buffer. The array is of length numStages+1. + * @param[in] pState points to the state buffer. The array is of length numStages+blockSize-1. + * @param[in] blockSize number of samples to process. + */ + void arm_iir_lattice_init_f32( + arm_iir_lattice_instance_f32 * S, + uint16_t numStages, + float32_t * pkCoeffs, + float32_t * pvCoeffs, + float32_t * pState, + uint32_t blockSize); + + + /** + * @brief Processing function for the Q31 IIR lattice filter. + * @param[in] S points to an instance of the Q31 IIR lattice structure. + * @param[in] pSrc points to the block of input data. + * @param[out] pDst points to the block of output data. + * @param[in] blockSize number of samples to process. + */ + void arm_iir_lattice_q31( + const arm_iir_lattice_instance_q31 * S, + q31_t * pSrc, + q31_t * pDst, + uint32_t blockSize); + + + /** + * @brief Initialization function for the Q31 IIR lattice filter. + * @param[in] S points to an instance of the Q31 IIR lattice structure. + * @param[in] numStages number of stages in the filter. + * @param[in] pkCoeffs points to the reflection coefficient buffer. The array is of length numStages. + * @param[in] pvCoeffs points to the ladder coefficient buffer. The array is of length numStages+1. + * @param[in] pState points to the state buffer. The array is of length numStages+blockSize. + * @param[in] blockSize number of samples to process. + */ + void arm_iir_lattice_init_q31( + arm_iir_lattice_instance_q31 * S, + uint16_t numStages, + q31_t * pkCoeffs, + q31_t * pvCoeffs, + q31_t * pState, + uint32_t blockSize); + + + /** + * @brief Processing function for the Q15 IIR lattice filter. + * @param[in] S points to an instance of the Q15 IIR lattice structure. + * @param[in] pSrc points to the block of input data. + * @param[out] pDst points to the block of output data. + * @param[in] blockSize number of samples to process. + */ + void arm_iir_lattice_q15( + const arm_iir_lattice_instance_q15 * S, + q15_t * pSrc, + q15_t * pDst, + uint32_t blockSize); + + +/** + * @brief Initialization function for the Q15 IIR lattice filter. + * @param[in] S points to an instance of the fixed-point Q15 IIR lattice structure. + * @param[in] numStages number of stages in the filter. + * @param[in] pkCoeffs points to reflection coefficient buffer. The array is of length numStages. + * @param[in] pvCoeffs points to ladder coefficient buffer. The array is of length numStages+1. + * @param[in] pState points to state buffer. The array is of length numStages+blockSize. + * @param[in] blockSize number of samples to process per call. + */ + void arm_iir_lattice_init_q15( + arm_iir_lattice_instance_q15 * S, + uint16_t numStages, + q15_t * pkCoeffs, + q15_t * pvCoeffs, + q15_t * pState, + uint32_t blockSize); + + + /** + * @brief Instance structure for the floating-point LMS filter. + */ + typedef struct + { + uint16_t numTaps; /**< number of coefficients in the filter. */ + float32_t *pState; /**< points to the state variable array. The array is of length numTaps+blockSize-1. */ + float32_t *pCoeffs; /**< points to the coefficient array. The array is of length numTaps. */ + float32_t mu; /**< step size that controls filter coefficient updates. */ + } arm_lms_instance_f32; + + + /** + * @brief Processing function for floating-point LMS filter. + * @param[in] S points to an instance of the floating-point LMS filter structure. + * @param[in] pSrc points to the block of input data. + * @param[in] pRef points to the block of reference data. + * @param[out] pOut points to the block of output data. + * @param[out] pErr points to the block of error data. + * @param[in] blockSize number of samples to process. + */ + void arm_lms_f32( + const arm_lms_instance_f32 * S, + float32_t * pSrc, + float32_t * pRef, + float32_t * pOut, + float32_t * pErr, + uint32_t blockSize); + + + /** + * @brief Initialization function for floating-point LMS filter. + * @param[in] S points to an instance of the floating-point LMS filter structure. + * @param[in] numTaps number of filter coefficients. + * @param[in] pCoeffs points to the coefficient buffer. + * @param[in] pState points to state buffer. + * @param[in] mu step size that controls filter coefficient updates. + * @param[in] blockSize number of samples to process. + */ + void arm_lms_init_f32( + arm_lms_instance_f32 * S, + uint16_t numTaps, + float32_t * pCoeffs, + float32_t * pState, + float32_t mu, + uint32_t blockSize); + + + /** + * @brief Instance structure for the Q15 LMS filter. + */ + typedef struct + { + uint16_t numTaps; /**< number of coefficients in the filter. */ + q15_t *pState; /**< points to the state variable array. The array is of length numTaps+blockSize-1. */ + q15_t *pCoeffs; /**< points to the coefficient array. The array is of length numTaps. */ + q15_t mu; /**< step size that controls filter coefficient updates. */ + uint32_t postShift; /**< bit shift applied to coefficients. */ + } arm_lms_instance_q15; + + + /** + * @brief Initialization function for the Q15 LMS filter. + * @param[in] S points to an instance of the Q15 LMS filter structure. + * @param[in] numTaps number of filter coefficients. + * @param[in] pCoeffs points to the coefficient buffer. + * @param[in] pState points to the state buffer. + * @param[in] mu step size that controls filter coefficient updates. + * @param[in] blockSize number of samples to process. + * @param[in] postShift bit shift applied to coefficients. + */ + void arm_lms_init_q15( + arm_lms_instance_q15 * S, + uint16_t numTaps, + q15_t * pCoeffs, + q15_t * pState, + q15_t mu, + uint32_t blockSize, + uint32_t postShift); + + + /** + * @brief Processing function for Q15 LMS filter. + * @param[in] S points to an instance of the Q15 LMS filter structure. + * @param[in] pSrc points to the block of input data. + * @param[in] pRef points to the block of reference data. + * @param[out] pOut points to the block of output data. + * @param[out] pErr points to the block of error data. + * @param[in] blockSize number of samples to process. + */ + void arm_lms_q15( + const arm_lms_instance_q15 * S, + q15_t * pSrc, + q15_t * pRef, + q15_t * pOut, + q15_t * pErr, + uint32_t blockSize); + + + /** + * @brief Instance structure for the Q31 LMS filter. + */ + typedef struct + { + uint16_t numTaps; /**< number of coefficients in the filter. */ + q31_t *pState; /**< points to the state variable array. The array is of length numTaps+blockSize-1. */ + q31_t *pCoeffs; /**< points to the coefficient array. The array is of length numTaps. */ + q31_t mu; /**< step size that controls filter coefficient updates. */ + uint32_t postShift; /**< bit shift applied to coefficients. */ + } arm_lms_instance_q31; + + + /** + * @brief Processing function for Q31 LMS filter. + * @param[in] S points to an instance of the Q15 LMS filter structure. + * @param[in] pSrc points to the block of input data. + * @param[in] pRef points to the block of reference data. + * @param[out] pOut points to the block of output data. + * @param[out] pErr points to the block of error data. + * @param[in] blockSize number of samples to process. + */ + void arm_lms_q31( + const arm_lms_instance_q31 * S, + q31_t * pSrc, + q31_t * pRef, + q31_t * pOut, + q31_t * pErr, + uint32_t blockSize); + + + /** + * @brief Initialization function for Q31 LMS filter. + * @param[in] S points to an instance of the Q31 LMS filter structure. + * @param[in] numTaps number of filter coefficients. + * @param[in] pCoeffs points to coefficient buffer. + * @param[in] pState points to state buffer. + * @param[in] mu step size that controls filter coefficient updates. + * @param[in] blockSize number of samples to process. + * @param[in] postShift bit shift applied to coefficients. + */ + void arm_lms_init_q31( + arm_lms_instance_q31 * S, + uint16_t numTaps, + q31_t * pCoeffs, + q31_t * pState, + q31_t mu, + uint32_t blockSize, + uint32_t postShift); + + + /** + * @brief Instance structure for the floating-point normalized LMS filter. + */ + typedef struct + { + uint16_t numTaps; /**< number of coefficients in the filter. */ + float32_t *pState; /**< points to the state variable array. The array is of length numTaps+blockSize-1. */ + float32_t *pCoeffs; /**< points to the coefficient array. The array is of length numTaps. */ + float32_t mu; /**< step size that control filter coefficient updates. */ + float32_t energy; /**< saves previous frame energy. */ + float32_t x0; /**< saves previous input sample. */ + } arm_lms_norm_instance_f32; + + + /** + * @brief Processing function for floating-point normalized LMS filter. + * @param[in] S points to an instance of the floating-point normalized LMS filter structure. + * @param[in] pSrc points to the block of input data. + * @param[in] pRef points to the block of reference data. + * @param[out] pOut points to the block of output data. + * @param[out] pErr points to the block of error data. + * @param[in] blockSize number of samples to process. + */ + void arm_lms_norm_f32( + arm_lms_norm_instance_f32 * S, + float32_t * pSrc, + float32_t * pRef, + float32_t * pOut, + float32_t * pErr, + uint32_t blockSize); + + + /** + * @brief Initialization function for floating-point normalized LMS filter. + * @param[in] S points to an instance of the floating-point LMS filter structure. + * @param[in] numTaps number of filter coefficients. + * @param[in] pCoeffs points to coefficient buffer. + * @param[in] pState points to state buffer. + * @param[in] mu step size that controls filter coefficient updates. + * @param[in] blockSize number of samples to process. + */ + void arm_lms_norm_init_f32( + arm_lms_norm_instance_f32 * S, + uint16_t numTaps, + float32_t * pCoeffs, + float32_t * pState, + float32_t mu, + uint32_t blockSize); + + + /** + * @brief Instance structure for the Q31 normalized LMS filter. + */ + typedef struct + { + uint16_t numTaps; /**< number of coefficients in the filter. */ + q31_t *pState; /**< points to the state variable array. The array is of length numTaps+blockSize-1. */ + q31_t *pCoeffs; /**< points to the coefficient array. The array is of length numTaps. */ + q31_t mu; /**< step size that controls filter coefficient updates. */ + uint8_t postShift; /**< bit shift applied to coefficients. */ + q31_t *recipTable; /**< points to the reciprocal initial value table. */ + q31_t energy; /**< saves previous frame energy. */ + q31_t x0; /**< saves previous input sample. */ + } arm_lms_norm_instance_q31; + + + /** + * @brief Processing function for Q31 normalized LMS filter. + * @param[in] S points to an instance of the Q31 normalized LMS filter structure. + * @param[in] pSrc points to the block of input data. + * @param[in] pRef points to the block of reference data. + * @param[out] pOut points to the block of output data. + * @param[out] pErr points to the block of error data. + * @param[in] blockSize number of samples to process. + */ + void arm_lms_norm_q31( + arm_lms_norm_instance_q31 * S, + q31_t * pSrc, + q31_t * pRef, + q31_t * pOut, + q31_t * pErr, + uint32_t blockSize); + + + /** + * @brief Initialization function for Q31 normalized LMS filter. + * @param[in] S points to an instance of the Q31 normalized LMS filter structure. + * @param[in] numTaps number of filter coefficients. + * @param[in] pCoeffs points to coefficient buffer. + * @param[in] pState points to state buffer. + * @param[in] mu step size that controls filter coefficient updates. + * @param[in] blockSize number of samples to process. + * @param[in] postShift bit shift applied to coefficients. + */ + void arm_lms_norm_init_q31( + arm_lms_norm_instance_q31 * S, + uint16_t numTaps, + q31_t * pCoeffs, + q31_t * pState, + q31_t mu, + uint32_t blockSize, + uint8_t postShift); + + + /** + * @brief Instance structure for the Q15 normalized LMS filter. + */ + typedef struct + { + uint16_t numTaps; /**< Number of coefficients in the filter. */ + q15_t *pState; /**< points to the state variable array. The array is of length numTaps+blockSize-1. */ + q15_t *pCoeffs; /**< points to the coefficient array. The array is of length numTaps. */ + q15_t mu; /**< step size that controls filter coefficient updates. */ + uint8_t postShift; /**< bit shift applied to coefficients. */ + q15_t *recipTable; /**< Points to the reciprocal initial value table. */ + q15_t energy; /**< saves previous frame energy. */ + q15_t x0; /**< saves previous input sample. */ + } arm_lms_norm_instance_q15; + + + /** + * @brief Processing function for Q15 normalized LMS filter. + * @param[in] S points to an instance of the Q15 normalized LMS filter structure. + * @param[in] pSrc points to the block of input data. + * @param[in] pRef points to the block of reference data. + * @param[out] pOut points to the block of output data. + * @param[out] pErr points to the block of error data. + * @param[in] blockSize number of samples to process. + */ + void arm_lms_norm_q15( + arm_lms_norm_instance_q15 * S, + q15_t * pSrc, + q15_t * pRef, + q15_t * pOut, + q15_t * pErr, + uint32_t blockSize); + + + /** + * @brief Initialization function for Q15 normalized LMS filter. + * @param[in] S points to an instance of the Q15 normalized LMS filter structure. + * @param[in] numTaps number of filter coefficients. + * @param[in] pCoeffs points to coefficient buffer. + * @param[in] pState points to state buffer. + * @param[in] mu step size that controls filter coefficient updates. + * @param[in] blockSize number of samples to process. + * @param[in] postShift bit shift applied to coefficients. + */ + void arm_lms_norm_init_q15( + arm_lms_norm_instance_q15 * S, + uint16_t numTaps, + q15_t * pCoeffs, + q15_t * pState, + q15_t mu, + uint32_t blockSize, + uint8_t postShift); + + + /** + * @brief Correlation of floating-point sequences. + * @param[in] pSrcA points to the first input sequence. + * @param[in] srcALen length of the first input sequence. + * @param[in] pSrcB points to the second input sequence. + * @param[in] srcBLen length of the second input sequence. + * @param[out] pDst points to the block of output data Length 2 * max(srcALen, srcBLen) - 1. + */ + void arm_correlate_f32( + float32_t * pSrcA, + uint32_t srcALen, + float32_t * pSrcB, + uint32_t srcBLen, + float32_t * pDst); + + + /** + * @brief Correlation of Q15 sequences + * @param[in] pSrcA points to the first input sequence. + * @param[in] srcALen length of the first input sequence. + * @param[in] pSrcB points to the second input sequence. + * @param[in] srcBLen length of the second input sequence. + * @param[out] pDst points to the block of output data Length 2 * max(srcALen, srcBLen) - 1. + * @param[in] pScratch points to scratch buffer of size max(srcALen, srcBLen) + 2*min(srcALen, srcBLen) - 2. + */ + void arm_correlate_opt_q15( + q15_t * pSrcA, + uint32_t srcALen, + q15_t * pSrcB, + uint32_t srcBLen, + q15_t * pDst, + q15_t * pScratch); + + + /** + * @brief Correlation of Q15 sequences. + * @param[in] pSrcA points to the first input sequence. + * @param[in] srcALen length of the first input sequence. + * @param[in] pSrcB points to the second input sequence. + * @param[in] srcBLen length of the second input sequence. + * @param[out] pDst points to the block of output data Length 2 * max(srcALen, srcBLen) - 1. + */ + + void arm_correlate_q15( + q15_t * pSrcA, + uint32_t srcALen, + q15_t * pSrcB, + uint32_t srcBLen, + q15_t * pDst); + + + /** + * @brief Correlation of Q15 sequences (fast version) for Cortex-M3 and Cortex-M4. + * @param[in] pSrcA points to the first input sequence. + * @param[in] srcALen length of the first input sequence. + * @param[in] pSrcB points to the second input sequence. + * @param[in] srcBLen length of the second input sequence. + * @param[out] pDst points to the block of output data Length 2 * max(srcALen, srcBLen) - 1. + */ + + void arm_correlate_fast_q15( + q15_t * pSrcA, + uint32_t srcALen, + q15_t * pSrcB, + uint32_t srcBLen, + q15_t * pDst); + + + /** + * @brief Correlation of Q15 sequences (fast version) for Cortex-M3 and Cortex-M4. + * @param[in] pSrcA points to the first input sequence. + * @param[in] srcALen length of the first input sequence. + * @param[in] pSrcB points to the second input sequence. + * @param[in] srcBLen length of the second input sequence. + * @param[out] pDst points to the block of output data Length 2 * max(srcALen, srcBLen) - 1. + * @param[in] pScratch points to scratch buffer of size max(srcALen, srcBLen) + 2*min(srcALen, srcBLen) - 2. + */ + void arm_correlate_fast_opt_q15( + q15_t * pSrcA, + uint32_t srcALen, + q15_t * pSrcB, + uint32_t srcBLen, + q15_t * pDst, + q15_t * pScratch); + + + /** + * @brief Correlation of Q31 sequences. + * @param[in] pSrcA points to the first input sequence. + * @param[in] srcALen length of the first input sequence. + * @param[in] pSrcB points to the second input sequence. + * @param[in] srcBLen length of the second input sequence. + * @param[out] pDst points to the block of output data Length 2 * max(srcALen, srcBLen) - 1. + */ + void arm_correlate_q31( + q31_t * pSrcA, + uint32_t srcALen, + q31_t * pSrcB, + uint32_t srcBLen, + q31_t * pDst); + + + /** + * @brief Correlation of Q31 sequences (fast version) for Cortex-M3 and Cortex-M4 + * @param[in] pSrcA points to the first input sequence. + * @param[in] srcALen length of the first input sequence. + * @param[in] pSrcB points to the second input sequence. + * @param[in] srcBLen length of the second input sequence. + * @param[out] pDst points to the block of output data Length 2 * max(srcALen, srcBLen) - 1. + */ + void arm_correlate_fast_q31( + q31_t * pSrcA, + uint32_t srcALen, + q31_t * pSrcB, + uint32_t srcBLen, + q31_t * pDst); + + + /** + * @brief Correlation of Q7 sequences. + * @param[in] pSrcA points to the first input sequence. + * @param[in] srcALen length of the first input sequence. + * @param[in] pSrcB points to the second input sequence. + * @param[in] srcBLen length of the second input sequence. + * @param[out] pDst points to the block of output data Length 2 * max(srcALen, srcBLen) - 1. + * @param[in] pScratch1 points to scratch buffer(of type q15_t) of size max(srcALen, srcBLen) + 2*min(srcALen, srcBLen) - 2. + * @param[in] pScratch2 points to scratch buffer (of type q15_t) of size min(srcALen, srcBLen). + */ + void arm_correlate_opt_q7( + q7_t * pSrcA, + uint32_t srcALen, + q7_t * pSrcB, + uint32_t srcBLen, + q7_t * pDst, + q15_t * pScratch1, + q15_t * pScratch2); + + + /** + * @brief Correlation of Q7 sequences. + * @param[in] pSrcA points to the first input sequence. + * @param[in] srcALen length of the first input sequence. + * @param[in] pSrcB points to the second input sequence. + * @param[in] srcBLen length of the second input sequence. + * @param[out] pDst points to the block of output data Length 2 * max(srcALen, srcBLen) - 1. + */ + void arm_correlate_q7( + q7_t * pSrcA, + uint32_t srcALen, + q7_t * pSrcB, + uint32_t srcBLen, + q7_t * pDst); + + + /** + * @brief Instance structure for the floating-point sparse FIR filter. + */ + typedef struct + { + uint16_t numTaps; /**< number of coefficients in the filter. */ + uint16_t stateIndex; /**< state buffer index. Points to the oldest sample in the state buffer. */ + float32_t *pState; /**< points to the state buffer array. The array is of length maxDelay+blockSize-1. */ + float32_t *pCoeffs; /**< points to the coefficient array. The array is of length numTaps.*/ + uint16_t maxDelay; /**< maximum offset specified by the pTapDelay array. */ + int32_t *pTapDelay; /**< points to the array of delay values. The array is of length numTaps. */ + } arm_fir_sparse_instance_f32; + + /** + * @brief Instance structure for the Q31 sparse FIR filter. + */ + typedef struct + { + uint16_t numTaps; /**< number of coefficients in the filter. */ + uint16_t stateIndex; /**< state buffer index. Points to the oldest sample in the state buffer. */ + q31_t *pState; /**< points to the state buffer array. The array is of length maxDelay+blockSize-1. */ + q31_t *pCoeffs; /**< points to the coefficient array. The array is of length numTaps.*/ + uint16_t maxDelay; /**< maximum offset specified by the pTapDelay array. */ + int32_t *pTapDelay; /**< points to the array of delay values. The array is of length numTaps. */ + } arm_fir_sparse_instance_q31; + + /** + * @brief Instance structure for the Q15 sparse FIR filter. + */ + typedef struct + { + uint16_t numTaps; /**< number of coefficients in the filter. */ + uint16_t stateIndex; /**< state buffer index. Points to the oldest sample in the state buffer. */ + q15_t *pState; /**< points to the state buffer array. The array is of length maxDelay+blockSize-1. */ + q15_t *pCoeffs; /**< points to the coefficient array. The array is of length numTaps.*/ + uint16_t maxDelay; /**< maximum offset specified by the pTapDelay array. */ + int32_t *pTapDelay; /**< points to the array of delay values. The array is of length numTaps. */ + } arm_fir_sparse_instance_q15; + + /** + * @brief Instance structure for the Q7 sparse FIR filter. + */ + typedef struct + { + uint16_t numTaps; /**< number of coefficients in the filter. */ + uint16_t stateIndex; /**< state buffer index. Points to the oldest sample in the state buffer. */ + q7_t *pState; /**< points to the state buffer array. The array is of length maxDelay+blockSize-1. */ + q7_t *pCoeffs; /**< points to the coefficient array. The array is of length numTaps.*/ + uint16_t maxDelay; /**< maximum offset specified by the pTapDelay array. */ + int32_t *pTapDelay; /**< points to the array of delay values. The array is of length numTaps. */ + } arm_fir_sparse_instance_q7; + + + /** + * @brief Processing function for the floating-point sparse FIR filter. + * @param[in] S points to an instance of the floating-point sparse FIR structure. + * @param[in] pSrc points to the block of input data. + * @param[out] pDst points to the block of output data + * @param[in] pScratchIn points to a temporary buffer of size blockSize. + * @param[in] blockSize number of input samples to process per call. + */ + void arm_fir_sparse_f32( + arm_fir_sparse_instance_f32 * S, + float32_t * pSrc, + float32_t * pDst, + float32_t * pScratchIn, + uint32_t blockSize); + + + /** + * @brief Initialization function for the floating-point sparse FIR filter. + * @param[in,out] S points to an instance of the floating-point sparse FIR structure. + * @param[in] numTaps number of nonzero coefficients in the filter. + * @param[in] pCoeffs points to the array of filter coefficients. + * @param[in] pState points to the state buffer. + * @param[in] pTapDelay points to the array of offset times. + * @param[in] maxDelay maximum offset time supported. + * @param[in] blockSize number of samples that will be processed per block. + */ + void arm_fir_sparse_init_f32( + arm_fir_sparse_instance_f32 * S, + uint16_t numTaps, + float32_t * pCoeffs, + float32_t * pState, + int32_t * pTapDelay, + uint16_t maxDelay, + uint32_t blockSize); + + + /** + * @brief Processing function for the Q31 sparse FIR filter. + * @param[in] S points to an instance of the Q31 sparse FIR structure. + * @param[in] pSrc points to the block of input data. + * @param[out] pDst points to the block of output data + * @param[in] pScratchIn points to a temporary buffer of size blockSize. + * @param[in] blockSize number of input samples to process per call. + */ + void arm_fir_sparse_q31( + arm_fir_sparse_instance_q31 * S, + q31_t * pSrc, + q31_t * pDst, + q31_t * pScratchIn, + uint32_t blockSize); + + + /** + * @brief Initialization function for the Q31 sparse FIR filter. + * @param[in,out] S points to an instance of the Q31 sparse FIR structure. + * @param[in] numTaps number of nonzero coefficients in the filter. + * @param[in] pCoeffs points to the array of filter coefficients. + * @param[in] pState points to the state buffer. + * @param[in] pTapDelay points to the array of offset times. + * @param[in] maxDelay maximum offset time supported. + * @param[in] blockSize number of samples that will be processed per block. + */ + void arm_fir_sparse_init_q31( + arm_fir_sparse_instance_q31 * S, + uint16_t numTaps, + q31_t * pCoeffs, + q31_t * pState, + int32_t * pTapDelay, + uint16_t maxDelay, + uint32_t blockSize); + + + /** + * @brief Processing function for the Q15 sparse FIR filter. + * @param[in] S points to an instance of the Q15 sparse FIR structure. + * @param[in] pSrc points to the block of input data. + * @param[out] pDst points to the block of output data + * @param[in] pScratchIn points to a temporary buffer of size blockSize. + * @param[in] pScratchOut points to a temporary buffer of size blockSize. + * @param[in] blockSize number of input samples to process per call. + */ + void arm_fir_sparse_q15( + arm_fir_sparse_instance_q15 * S, + q15_t * pSrc, + q15_t * pDst, + q15_t * pScratchIn, + q31_t * pScratchOut, + uint32_t blockSize); + + + /** + * @brief Initialization function for the Q15 sparse FIR filter. + * @param[in,out] S points to an instance of the Q15 sparse FIR structure. + * @param[in] numTaps number of nonzero coefficients in the filter. + * @param[in] pCoeffs points to the array of filter coefficients. + * @param[in] pState points to the state buffer. + * @param[in] pTapDelay points to the array of offset times. + * @param[in] maxDelay maximum offset time supported. + * @param[in] blockSize number of samples that will be processed per block. + */ + void arm_fir_sparse_init_q15( + arm_fir_sparse_instance_q15 * S, + uint16_t numTaps, + q15_t * pCoeffs, + q15_t * pState, + int32_t * pTapDelay, + uint16_t maxDelay, + uint32_t blockSize); + + + /** + * @brief Processing function for the Q7 sparse FIR filter. + * @param[in] S points to an instance of the Q7 sparse FIR structure. + * @param[in] pSrc points to the block of input data. + * @param[out] pDst points to the block of output data + * @param[in] pScratchIn points to a temporary buffer of size blockSize. + * @param[in] pScratchOut points to a temporary buffer of size blockSize. + * @param[in] blockSize number of input samples to process per call. + */ + void arm_fir_sparse_q7( + arm_fir_sparse_instance_q7 * S, + q7_t * pSrc, + q7_t * pDst, + q7_t * pScratchIn, + q31_t * pScratchOut, + uint32_t blockSize); + + + /** + * @brief Initialization function for the Q7 sparse FIR filter. + * @param[in,out] S points to an instance of the Q7 sparse FIR structure. + * @param[in] numTaps number of nonzero coefficients in the filter. + * @param[in] pCoeffs points to the array of filter coefficients. + * @param[in] pState points to the state buffer. + * @param[in] pTapDelay points to the array of offset times. + * @param[in] maxDelay maximum offset time supported. + * @param[in] blockSize number of samples that will be processed per block. + */ + void arm_fir_sparse_init_q7( + arm_fir_sparse_instance_q7 * S, + uint16_t numTaps, + q7_t * pCoeffs, + q7_t * pState, + int32_t * pTapDelay, + uint16_t maxDelay, + uint32_t blockSize); + + + /** + * @brief Floating-point sin_cos function. + * @param[in] theta input value in degrees + * @param[out] pSinVal points to the processed sine output. + * @param[out] pCosVal points to the processed cos output. + */ + void arm_sin_cos_f32( + float32_t theta, + float32_t * pSinVal, + float32_t * pCosVal); + + + /** + * @brief Q31 sin_cos function. + * @param[in] theta scaled input value in degrees + * @param[out] pSinVal points to the processed sine output. + * @param[out] pCosVal points to the processed cosine output. + */ + void arm_sin_cos_q31( + q31_t theta, + q31_t * pSinVal, + q31_t * pCosVal); + + + /** + * @brief Floating-point complex conjugate. + * @param[in] pSrc points to the input vector + * @param[out] pDst points to the output vector + * @param[in] numSamples number of complex samples in each vector + */ + void arm_cmplx_conj_f32( + float32_t * pSrc, + float32_t * pDst, + uint32_t numSamples); + + /** + * @brief Q31 complex conjugate. + * @param[in] pSrc points to the input vector + * @param[out] pDst points to the output vector + * @param[in] numSamples number of complex samples in each vector + */ + void arm_cmplx_conj_q31( + q31_t * pSrc, + q31_t * pDst, + uint32_t numSamples); + + + /** + * @brief Q15 complex conjugate. + * @param[in] pSrc points to the input vector + * @param[out] pDst points to the output vector + * @param[in] numSamples number of complex samples in each vector + */ + void arm_cmplx_conj_q15( + q15_t * pSrc, + q15_t * pDst, + uint32_t numSamples); + + + /** + * @brief Floating-point complex magnitude squared + * @param[in] pSrc points to the complex input vector + * @param[out] pDst points to the real output vector + * @param[in] numSamples number of complex samples in the input vector + */ + void arm_cmplx_mag_squared_f32( + float32_t * pSrc, + float32_t * pDst, + uint32_t numSamples); + + + /** + * @brief Q31 complex magnitude squared + * @param[in] pSrc points to the complex input vector + * @param[out] pDst points to the real output vector + * @param[in] numSamples number of complex samples in the input vector + */ + void arm_cmplx_mag_squared_q31( + q31_t * pSrc, + q31_t * pDst, + uint32_t numSamples); + + + /** + * @brief Q15 complex magnitude squared + * @param[in] pSrc points to the complex input vector + * @param[out] pDst points to the real output vector + * @param[in] numSamples number of complex samples in the input vector + */ + void arm_cmplx_mag_squared_q15( + q15_t * pSrc, + q15_t * pDst, + uint32_t numSamples); + + + /** + * @ingroup groupController + */ + + /** + * @defgroup PID PID Motor Control + * + * A Proportional Integral Derivative (PID) controller is a generic feedback control + * loop mechanism widely used in industrial control systems. + * A PID controller is the most commonly used type of feedback controller. + * + * This set of functions implements (PID) controllers + * for Q15, Q31, and floating-point data types. The functions operate on a single sample + * of data and each call to the function returns a single processed value. + * S points to an instance of the PID control data structure. in + * is the input sample value. The functions return the output value. + * + * \par Algorithm: + *
    +   *    y[n] = y[n-1] + A0 * x[n] + A1 * x[n-1] + A2 * x[n-2]
    +   *    A0 = Kp + Ki + Kd
    +   *    A1 = (-Kp ) - (2 * Kd )
    +   *    A2 = Kd  
    + * + * \par + * where \c Kp is proportional constant, \c Ki is Integral constant and \c Kd is Derivative constant + * + * \par + * \image html PID.gif "Proportional Integral Derivative Controller" + * + * \par + * The PID controller calculates an "error" value as the difference between + * the measured output and the reference input. + * The controller attempts to minimize the error by adjusting the process control inputs. + * The proportional value determines the reaction to the current error, + * the integral value determines the reaction based on the sum of recent errors, + * and the derivative value determines the reaction based on the rate at which the error has been changing. + * + * \par Instance Structure + * The Gains A0, A1, A2 and state variables for a PID controller are stored together in an instance data structure. + * A separate instance structure must be defined for each PID Controller. + * There are separate instance structure declarations for each of the 3 supported data types. + * + * \par Reset Functions + * There is also an associated reset function for each data type which clears the state array. + * + * \par Initialization Functions + * There is also an associated initialization function for each data type. + * The initialization function performs the following operations: + * - Initializes the Gains A0, A1, A2 from Kp,Ki, Kd gains. + * - Zeros out the values in the state buffer. + * + * \par + * Instance structure cannot be placed into a const data section and it is recommended to use the initialization function. + * + * \par Fixed-Point Behavior + * Care must be taken when using the fixed-point versions of the PID Controller functions. + * In particular, the overflow and saturation behavior of the accumulator used in each function must be considered. + * Refer to the function specific documentation below for usage guidelines. + */ + + /** + * @addtogroup PID + * @{ + */ + + /** + * @brief Process function for the floating-point PID Control. + * @param[in,out] S is an instance of the floating-point PID Control structure + * @param[in] in input sample to process + * @return out processed output sample. + */ + CMSIS_INLINE __STATIC_INLINE float32_t arm_pid_f32( + arm_pid_instance_f32 * S, + float32_t in) + { + float32_t out; + + /* y[n] = y[n-1] + A0 * x[n] + A1 * x[n-1] + A2 * x[n-2] */ + out = (S->A0 * in) + + (S->A1 * S->state[0]) + (S->A2 * S->state[1]) + (S->state[2]); + + /* Update state */ + S->state[1] = S->state[0]; + S->state[0] = in; + S->state[2] = out; + + /* return to application */ + return (out); + + } + + /** + * @brief Process function for the Q31 PID Control. + * @param[in,out] S points to an instance of the Q31 PID Control structure + * @param[in] in input sample to process + * @return out processed output sample. + * + * Scaling and Overflow Behavior: + * \par + * The function is implemented using an internal 64-bit accumulator. + * The accumulator has a 2.62 format and maintains full precision of the intermediate multiplication results but provides only a single guard bit. + * Thus, if the accumulator result overflows it wraps around rather than clip. + * In order to avoid overflows completely the input signal must be scaled down by 2 bits as there are four additions. + * After all multiply-accumulates are performed, the 2.62 accumulator is truncated to 1.32 format and then saturated to 1.31 format. + */ + CMSIS_INLINE __STATIC_INLINE q31_t arm_pid_q31( + arm_pid_instance_q31 * S, + q31_t in) + { + q63_t acc; + q31_t out; + + /* acc = A0 * x[n] */ + acc = (q63_t) S->A0 * in; + + /* acc += A1 * x[n-1] */ + acc += (q63_t) S->A1 * S->state[0]; + + /* acc += A2 * x[n-2] */ + acc += (q63_t) S->A2 * S->state[1]; + + /* convert output to 1.31 format to add y[n-1] */ + out = (q31_t) (acc >> 31U); + + /* out += y[n-1] */ + out += S->state[2]; + + /* Update state */ + S->state[1] = S->state[0]; + S->state[0] = in; + S->state[2] = out; + + /* return to application */ + return (out); + } + + + /** + * @brief Process function for the Q15 PID Control. + * @param[in,out] S points to an instance of the Q15 PID Control structure + * @param[in] in input sample to process + * @return out processed output sample. + * + * Scaling and Overflow Behavior: + * \par + * The function is implemented using a 64-bit internal accumulator. + * Both Gains and state variables are represented in 1.15 format and multiplications yield a 2.30 result. + * The 2.30 intermediate results are accumulated in a 64-bit accumulator in 34.30 format. + * There is no risk of internal overflow with this approach and the full precision of intermediate multiplications is preserved. + * After all additions have been performed, the accumulator is truncated to 34.15 format by discarding low 15 bits. + * Lastly, the accumulator is saturated to yield a result in 1.15 format. + */ + CMSIS_INLINE __STATIC_INLINE q15_t arm_pid_q15( + arm_pid_instance_q15 * S, + q15_t in) + { + q63_t acc; + q15_t out; + +#if defined (ARM_MATH_DSP) + __SIMD32_TYPE *vstate; + + /* Implementation of PID controller */ + + /* acc = A0 * x[n] */ + acc = (q31_t) __SMUAD((uint32_t)S->A0, (uint32_t)in); + + /* acc += A1 * x[n-1] + A2 * x[n-2] */ + vstate = __SIMD32_CONST(S->state); + acc = (q63_t)__SMLALD((uint32_t)S->A1, (uint32_t)*vstate, (uint64_t)acc); +#else + /* acc = A0 * x[n] */ + acc = ((q31_t) S->A0) * in; + + /* acc += A1 * x[n-1] + A2 * x[n-2] */ + acc += (q31_t) S->A1 * S->state[0]; + acc += (q31_t) S->A2 * S->state[1]; +#endif + + /* acc += y[n-1] */ + acc += (q31_t) S->state[2] << 15; + + /* saturate the output */ + out = (q15_t) (__SSAT((acc >> 15), 16)); + + /* Update state */ + S->state[1] = S->state[0]; + S->state[0] = in; + S->state[2] = out; + + /* return to application */ + return (out); + } + + /** + * @} end of PID group + */ + + + /** + * @brief Floating-point matrix inverse. + * @param[in] src points to the instance of the input floating-point matrix structure. + * @param[out] dst points to the instance of the output floating-point matrix structure. + * @return The function returns ARM_MATH_SIZE_MISMATCH, if the dimensions do not match. + * If the input matrix is singular (does not have an inverse), then the algorithm terminates and returns error status ARM_MATH_SINGULAR. + */ + arm_status arm_mat_inverse_f32( + const arm_matrix_instance_f32 * src, + arm_matrix_instance_f32 * dst); + + + /** + * @brief Floating-point matrix inverse. + * @param[in] src points to the instance of the input floating-point matrix structure. + * @param[out] dst points to the instance of the output floating-point matrix structure. + * @return The function returns ARM_MATH_SIZE_MISMATCH, if the dimensions do not match. + * If the input matrix is singular (does not have an inverse), then the algorithm terminates and returns error status ARM_MATH_SINGULAR. + */ + arm_status arm_mat_inverse_f64( + const arm_matrix_instance_f64 * src, + arm_matrix_instance_f64 * dst); + + + + /** + * @ingroup groupController + */ + + /** + * @defgroup clarke Vector Clarke Transform + * Forward Clarke transform converts the instantaneous stator phases into a two-coordinate time invariant vector. + * Generally the Clarke transform uses three-phase currents Ia, Ib and Ic to calculate currents + * in the two-phase orthogonal stator axis Ialpha and Ibeta. + * When Ialpha is superposed with Ia as shown in the figure below + * \image html clarke.gif Stator current space vector and its components in (a,b). + * and Ia + Ib + Ic = 0, in this condition Ialpha and Ibeta + * can be calculated using only Ia and Ib. + * + * The function operates on a single sample of data and each call to the function returns the processed output. + * The library provides separate functions for Q31 and floating-point data types. + * \par Algorithm + * \image html clarkeFormula.gif + * where Ia and Ib are the instantaneous stator phases and + * pIalpha and pIbeta are the two coordinates of time invariant vector. + * \par Fixed-Point Behavior + * Care must be taken when using the Q31 version of the Clarke transform. + * In particular, the overflow and saturation behavior of the accumulator used must be considered. + * Refer to the function specific documentation below for usage guidelines. + */ + + /** + * @addtogroup clarke + * @{ + */ + + /** + * + * @brief Floating-point Clarke transform + * @param[in] Ia input three-phase coordinate a + * @param[in] Ib input three-phase coordinate b + * @param[out] pIalpha points to output two-phase orthogonal vector axis alpha + * @param[out] pIbeta points to output two-phase orthogonal vector axis beta + */ + CMSIS_INLINE __STATIC_INLINE void arm_clarke_f32( + float32_t Ia, + float32_t Ib, + float32_t * pIalpha, + float32_t * pIbeta) + { + /* Calculate pIalpha using the equation, pIalpha = Ia */ + *pIalpha = Ia; + + /* Calculate pIbeta using the equation, pIbeta = (1/sqrt(3)) * Ia + (2/sqrt(3)) * Ib */ + *pIbeta = ((float32_t) 0.57735026919 * Ia + (float32_t) 1.15470053838 * Ib); + } + + + /** + * @brief Clarke transform for Q31 version + * @param[in] Ia input three-phase coordinate a + * @param[in] Ib input three-phase coordinate b + * @param[out] pIalpha points to output two-phase orthogonal vector axis alpha + * @param[out] pIbeta points to output two-phase orthogonal vector axis beta + * + * Scaling and Overflow Behavior: + * \par + * The function is implemented using an internal 32-bit accumulator. + * The accumulator maintains 1.31 format by truncating lower 31 bits of the intermediate multiplication in 2.62 format. + * There is saturation on the addition, hence there is no risk of overflow. + */ + CMSIS_INLINE __STATIC_INLINE void arm_clarke_q31( + q31_t Ia, + q31_t Ib, + q31_t * pIalpha, + q31_t * pIbeta) + { + q31_t product1, product2; /* Temporary variables used to store intermediate results */ + + /* Calculating pIalpha from Ia by equation pIalpha = Ia */ + *pIalpha = Ia; + + /* Intermediate product is calculated by (1/(sqrt(3)) * Ia) */ + product1 = (q31_t) (((q63_t) Ia * 0x24F34E8B) >> 30); + + /* Intermediate product is calculated by (2/sqrt(3) * Ib) */ + product2 = (q31_t) (((q63_t) Ib * 0x49E69D16) >> 30); + + /* pIbeta is calculated by adding the intermediate products */ + *pIbeta = __QADD(product1, product2); + } + + /** + * @} end of clarke group + */ + + /** + * @brief Converts the elements of the Q7 vector to Q31 vector. + * @param[in] pSrc input pointer + * @param[out] pDst output pointer + * @param[in] blockSize number of samples to process + */ + void arm_q7_to_q31( + q7_t * pSrc, + q31_t * pDst, + uint32_t blockSize); + + + + /** + * @ingroup groupController + */ + + /** + * @defgroup inv_clarke Vector Inverse Clarke Transform + * Inverse Clarke transform converts the two-coordinate time invariant vector into instantaneous stator phases. + * + * The function operates on a single sample of data and each call to the function returns the processed output. + * The library provides separate functions for Q31 and floating-point data types. + * \par Algorithm + * \image html clarkeInvFormula.gif + * where pIa and pIb are the instantaneous stator phases and + * Ialpha and Ibeta are the two coordinates of time invariant vector. + * \par Fixed-Point Behavior + * Care must be taken when using the Q31 version of the Clarke transform. + * In particular, the overflow and saturation behavior of the accumulator used must be considered. + * Refer to the function specific documentation below for usage guidelines. + */ + + /** + * @addtogroup inv_clarke + * @{ + */ + + /** + * @brief Floating-point Inverse Clarke transform + * @param[in] Ialpha input two-phase orthogonal vector axis alpha + * @param[in] Ibeta input two-phase orthogonal vector axis beta + * @param[out] pIa points to output three-phase coordinate a + * @param[out] pIb points to output three-phase coordinate b + */ + CMSIS_INLINE __STATIC_INLINE void arm_inv_clarke_f32( + float32_t Ialpha, + float32_t Ibeta, + float32_t * pIa, + float32_t * pIb) + { + /* Calculating pIa from Ialpha by equation pIa = Ialpha */ + *pIa = Ialpha; + + /* Calculating pIb from Ialpha and Ibeta by equation pIb = -(1/2) * Ialpha + (sqrt(3)/2) * Ibeta */ + *pIb = -0.5f * Ialpha + 0.8660254039f * Ibeta; + } + + + /** + * @brief Inverse Clarke transform for Q31 version + * @param[in] Ialpha input two-phase orthogonal vector axis alpha + * @param[in] Ibeta input two-phase orthogonal vector axis beta + * @param[out] pIa points to output three-phase coordinate a + * @param[out] pIb points to output three-phase coordinate b + * + * Scaling and Overflow Behavior: + * \par + * The function is implemented using an internal 32-bit accumulator. + * The accumulator maintains 1.31 format by truncating lower 31 bits of the intermediate multiplication in 2.62 format. + * There is saturation on the subtraction, hence there is no risk of overflow. + */ + CMSIS_INLINE __STATIC_INLINE void arm_inv_clarke_q31( + q31_t Ialpha, + q31_t Ibeta, + q31_t * pIa, + q31_t * pIb) + { + q31_t product1, product2; /* Temporary variables used to store intermediate results */ + + /* Calculating pIa from Ialpha by equation pIa = Ialpha */ + *pIa = Ialpha; + + /* Intermediate product is calculated by (1/(2*sqrt(3)) * Ia) */ + product1 = (q31_t) (((q63_t) (Ialpha) * (0x40000000)) >> 31); + + /* Intermediate product is calculated by (1/sqrt(3) * pIb) */ + product2 = (q31_t) (((q63_t) (Ibeta) * (0x6ED9EBA1)) >> 31); + + /* pIb is calculated by subtracting the products */ + *pIb = __QSUB(product2, product1); + } + + /** + * @} end of inv_clarke group + */ + + /** + * @brief Converts the elements of the Q7 vector to Q15 vector. + * @param[in] pSrc input pointer + * @param[out] pDst output pointer + * @param[in] blockSize number of samples to process + */ + void arm_q7_to_q15( + q7_t * pSrc, + q15_t * pDst, + uint32_t blockSize); + + + + /** + * @ingroup groupController + */ + + /** + * @defgroup park Vector Park Transform + * + * Forward Park transform converts the input two-coordinate vector to flux and torque components. + * The Park transform can be used to realize the transformation of the Ialpha and the Ibeta currents + * from the stationary to the moving reference frame and control the spatial relationship between + * the stator vector current and rotor flux vector. + * If we consider the d axis aligned with the rotor flux, the diagram below shows the + * current vector and the relationship from the two reference frames: + * \image html park.gif "Stator current space vector and its component in (a,b) and in the d,q rotating reference frame" + * + * The function operates on a single sample of data and each call to the function returns the processed output. + * The library provides separate functions for Q31 and floating-point data types. + * \par Algorithm + * \image html parkFormula.gif + * where Ialpha and Ibeta are the stator vector components, + * pId and pIq are rotor vector components and cosVal and sinVal are the + * cosine and sine values of theta (rotor flux position). + * \par Fixed-Point Behavior + * Care must be taken when using the Q31 version of the Park transform. + * In particular, the overflow and saturation behavior of the accumulator used must be considered. + * Refer to the function specific documentation below for usage guidelines. + */ + + /** + * @addtogroup park + * @{ + */ + + /** + * @brief Floating-point Park transform + * @param[in] Ialpha input two-phase vector coordinate alpha + * @param[in] Ibeta input two-phase vector coordinate beta + * @param[out] pId points to output rotor reference frame d + * @param[out] pIq points to output rotor reference frame q + * @param[in] sinVal sine value of rotation angle theta + * @param[in] cosVal cosine value of rotation angle theta + * + * The function implements the forward Park transform. + * + */ + CMSIS_INLINE __STATIC_INLINE void arm_park_f32( + float32_t Ialpha, + float32_t Ibeta, + float32_t * pId, + float32_t * pIq, + float32_t sinVal, + float32_t cosVal) + { + /* Calculate pId using the equation, pId = Ialpha * cosVal + Ibeta * sinVal */ + *pId = Ialpha * cosVal + Ibeta * sinVal; + + /* Calculate pIq using the equation, pIq = - Ialpha * sinVal + Ibeta * cosVal */ + *pIq = -Ialpha * sinVal + Ibeta * cosVal; + } + + + /** + * @brief Park transform for Q31 version + * @param[in] Ialpha input two-phase vector coordinate alpha + * @param[in] Ibeta input two-phase vector coordinate beta + * @param[out] pId points to output rotor reference frame d + * @param[out] pIq points to output rotor reference frame q + * @param[in] sinVal sine value of rotation angle theta + * @param[in] cosVal cosine value of rotation angle theta + * + * Scaling and Overflow Behavior: + * \par + * The function is implemented using an internal 32-bit accumulator. + * The accumulator maintains 1.31 format by truncating lower 31 bits of the intermediate multiplication in 2.62 format. + * There is saturation on the addition and subtraction, hence there is no risk of overflow. + */ + CMSIS_INLINE __STATIC_INLINE void arm_park_q31( + q31_t Ialpha, + q31_t Ibeta, + q31_t * pId, + q31_t * pIq, + q31_t sinVal, + q31_t cosVal) + { + q31_t product1, product2; /* Temporary variables used to store intermediate results */ + q31_t product3, product4; /* Temporary variables used to store intermediate results */ + + /* Intermediate product is calculated by (Ialpha * cosVal) */ + product1 = (q31_t) (((q63_t) (Ialpha) * (cosVal)) >> 31); + + /* Intermediate product is calculated by (Ibeta * sinVal) */ + product2 = (q31_t) (((q63_t) (Ibeta) * (sinVal)) >> 31); + + + /* Intermediate product is calculated by (Ialpha * sinVal) */ + product3 = (q31_t) (((q63_t) (Ialpha) * (sinVal)) >> 31); + + /* Intermediate product is calculated by (Ibeta * cosVal) */ + product4 = (q31_t) (((q63_t) (Ibeta) * (cosVal)) >> 31); + + /* Calculate pId by adding the two intermediate products 1 and 2 */ + *pId = __QADD(product1, product2); + + /* Calculate pIq by subtracting the two intermediate products 3 from 4 */ + *pIq = __QSUB(product4, product3); + } + + /** + * @} end of park group + */ + + /** + * @brief Converts the elements of the Q7 vector to floating-point vector. + * @param[in] pSrc is input pointer + * @param[out] pDst is output pointer + * @param[in] blockSize is the number of samples to process + */ + void arm_q7_to_float( + q7_t * pSrc, + float32_t * pDst, + uint32_t blockSize); + + + /** + * @ingroup groupController + */ + + /** + * @defgroup inv_park Vector Inverse Park transform + * Inverse Park transform converts the input flux and torque components to two-coordinate vector. + * + * The function operates on a single sample of data and each call to the function returns the processed output. + * The library provides separate functions for Q31 and floating-point data types. + * \par Algorithm + * \image html parkInvFormula.gif + * where pIalpha and pIbeta are the stator vector components, + * Id and Iq are rotor vector components and cosVal and sinVal are the + * cosine and sine values of theta (rotor flux position). + * \par Fixed-Point Behavior + * Care must be taken when using the Q31 version of the Park transform. + * In particular, the overflow and saturation behavior of the accumulator used must be considered. + * Refer to the function specific documentation below for usage guidelines. + */ + + /** + * @addtogroup inv_park + * @{ + */ + + /** + * @brief Floating-point Inverse Park transform + * @param[in] Id input coordinate of rotor reference frame d + * @param[in] Iq input coordinate of rotor reference frame q + * @param[out] pIalpha points to output two-phase orthogonal vector axis alpha + * @param[out] pIbeta points to output two-phase orthogonal vector axis beta + * @param[in] sinVal sine value of rotation angle theta + * @param[in] cosVal cosine value of rotation angle theta + */ + CMSIS_INLINE __STATIC_INLINE void arm_inv_park_f32( + float32_t Id, + float32_t Iq, + float32_t * pIalpha, + float32_t * pIbeta, + float32_t sinVal, + float32_t cosVal) + { + /* Calculate pIalpha using the equation, pIalpha = Id * cosVal - Iq * sinVal */ + *pIalpha = Id * cosVal - Iq * sinVal; + + /* Calculate pIbeta using the equation, pIbeta = Id * sinVal + Iq * cosVal */ + *pIbeta = Id * sinVal + Iq * cosVal; + } + + + /** + * @brief Inverse Park transform for Q31 version + * @param[in] Id input coordinate of rotor reference frame d + * @param[in] Iq input coordinate of rotor reference frame q + * @param[out] pIalpha points to output two-phase orthogonal vector axis alpha + * @param[out] pIbeta points to output two-phase orthogonal vector axis beta + * @param[in] sinVal sine value of rotation angle theta + * @param[in] cosVal cosine value of rotation angle theta + * + * Scaling and Overflow Behavior: + * \par + * The function is implemented using an internal 32-bit accumulator. + * The accumulator maintains 1.31 format by truncating lower 31 bits of the intermediate multiplication in 2.62 format. + * There is saturation on the addition, hence there is no risk of overflow. + */ + CMSIS_INLINE __STATIC_INLINE void arm_inv_park_q31( + q31_t Id, + q31_t Iq, + q31_t * pIalpha, + q31_t * pIbeta, + q31_t sinVal, + q31_t cosVal) + { + q31_t product1, product2; /* Temporary variables used to store intermediate results */ + q31_t product3, product4; /* Temporary variables used to store intermediate results */ + + /* Intermediate product is calculated by (Id * cosVal) */ + product1 = (q31_t) (((q63_t) (Id) * (cosVal)) >> 31); + + /* Intermediate product is calculated by (Iq * sinVal) */ + product2 = (q31_t) (((q63_t) (Iq) * (sinVal)) >> 31); + + + /* Intermediate product is calculated by (Id * sinVal) */ + product3 = (q31_t) (((q63_t) (Id) * (sinVal)) >> 31); + + /* Intermediate product is calculated by (Iq * cosVal) */ + product4 = (q31_t) (((q63_t) (Iq) * (cosVal)) >> 31); + + /* Calculate pIalpha by using the two intermediate products 1 and 2 */ + *pIalpha = __QSUB(product1, product2); + + /* Calculate pIbeta by using the two intermediate products 3 and 4 */ + *pIbeta = __QADD(product4, product3); + } + + /** + * @} end of Inverse park group + */ + + + /** + * @brief Converts the elements of the Q31 vector to floating-point vector. + * @param[in] pSrc is input pointer + * @param[out] pDst is output pointer + * @param[in] blockSize is the number of samples to process + */ + void arm_q31_to_float( + q31_t * pSrc, + float32_t * pDst, + uint32_t blockSize); + + /** + * @ingroup groupInterpolation + */ + + /** + * @defgroup LinearInterpolate Linear Interpolation + * + * Linear interpolation is a method of curve fitting using linear polynomials. + * Linear interpolation works by effectively drawing a straight line between two neighboring samples and returning the appropriate point along that line + * + * \par + * \image html LinearInterp.gif "Linear interpolation" + * + * \par + * A Linear Interpolate function calculates an output value(y), for the input(x) + * using linear interpolation of the input values x0, x1( nearest input values) and the output values y0 and y1(nearest output values) + * + * \par Algorithm: + *
    +   *       y = y0 + (x - x0) * ((y1 - y0)/(x1-x0))
    +   *       where x0, x1 are nearest values of input x
    +   *             y0, y1 are nearest values to output y
    +   * 
    + * + * \par + * This set of functions implements Linear interpolation process + * for Q7, Q15, Q31, and floating-point data types. The functions operate on a single + * sample of data and each call to the function returns a single processed value. + * S points to an instance of the Linear Interpolate function data structure. + * x is the input sample value. The functions returns the output value. + * + * \par + * if x is outside of the table boundary, Linear interpolation returns first value of the table + * if x is below input range and returns last value of table if x is above range. + */ + + /** + * @addtogroup LinearInterpolate + * @{ + */ + + /** + * @brief Process function for the floating-point Linear Interpolation Function. + * @param[in,out] S is an instance of the floating-point Linear Interpolation structure + * @param[in] x input sample to process + * @return y processed output sample. + * + */ + CMSIS_INLINE __STATIC_INLINE float32_t arm_linear_interp_f32( + arm_linear_interp_instance_f32 * S, + float32_t x) + { + float32_t y; + float32_t x0, x1; /* Nearest input values */ + float32_t y0, y1; /* Nearest output values */ + float32_t xSpacing = S->xSpacing; /* spacing between input values */ + int32_t i; /* Index variable */ + float32_t *pYData = S->pYData; /* pointer to output table */ + + /* Calculation of index */ + i = (int32_t) ((x - S->x1) / xSpacing); + + if (i < 0) + { + /* Iniatilize output for below specified range as least output value of table */ + y = pYData[0]; + } + else if ((uint32_t)i >= S->nValues) + { + /* Iniatilize output for above specified range as last output value of table */ + y = pYData[S->nValues - 1]; + } + else + { + /* Calculation of nearest input values */ + x0 = S->x1 + i * xSpacing; + x1 = S->x1 + (i + 1) * xSpacing; + + /* Read of nearest output values */ + y0 = pYData[i]; + y1 = pYData[i + 1]; + + /* Calculation of output */ + y = y0 + (x - x0) * ((y1 - y0) / (x1 - x0)); + + } + + /* returns output value */ + return (y); + } + + + /** + * + * @brief Process function for the Q31 Linear Interpolation Function. + * @param[in] pYData pointer to Q31 Linear Interpolation table + * @param[in] x input sample to process + * @param[in] nValues number of table values + * @return y processed output sample. + * + * \par + * Input sample x is in 12.20 format which contains 12 bits for table index and 20 bits for fractional part. + * This function can support maximum of table size 2^12. + * + */ + CMSIS_INLINE __STATIC_INLINE q31_t arm_linear_interp_q31( + q31_t * pYData, + q31_t x, + uint32_t nValues) + { + q31_t y; /* output */ + q31_t y0, y1; /* Nearest output values */ + q31_t fract; /* fractional part */ + int32_t index; /* Index to read nearest output values */ + + /* Input is in 12.20 format */ + /* 12 bits for the table index */ + /* Index value calculation */ + index = ((x & (q31_t)0xFFF00000) >> 20); + + if (index >= (int32_t)(nValues - 1)) + { + return (pYData[nValues - 1]); + } + else if (index < 0) + { + return (pYData[0]); + } + else + { + /* 20 bits for the fractional part */ + /* shift left by 11 to keep fract in 1.31 format */ + fract = (x & 0x000FFFFF) << 11; + + /* Read two nearest output values from the index in 1.31(q31) format */ + y0 = pYData[index]; + y1 = pYData[index + 1]; + + /* Calculation of y0 * (1-fract) and y is in 2.30 format */ + y = ((q31_t) ((q63_t) y0 * (0x7FFFFFFF - fract) >> 32)); + + /* Calculation of y0 * (1-fract) + y1 *fract and y is in 2.30 format */ + y += ((q31_t) (((q63_t) y1 * fract) >> 32)); + + /* Convert y to 1.31 format */ + return (y << 1U); + } + } + + + /** + * + * @brief Process function for the Q15 Linear Interpolation Function. + * @param[in] pYData pointer to Q15 Linear Interpolation table + * @param[in] x input sample to process + * @param[in] nValues number of table values + * @return y processed output sample. + * + * \par + * Input sample x is in 12.20 format which contains 12 bits for table index and 20 bits for fractional part. + * This function can support maximum of table size 2^12. + * + */ + CMSIS_INLINE __STATIC_INLINE q15_t arm_linear_interp_q15( + q15_t * pYData, + q31_t x, + uint32_t nValues) + { + q63_t y; /* output */ + q15_t y0, y1; /* Nearest output values */ + q31_t fract; /* fractional part */ + int32_t index; /* Index to read nearest output values */ + + /* Input is in 12.20 format */ + /* 12 bits for the table index */ + /* Index value calculation */ + index = ((x & (int32_t)0xFFF00000) >> 20); + + if (index >= (int32_t)(nValues - 1)) + { + return (pYData[nValues - 1]); + } + else if (index < 0) + { + return (pYData[0]); + } + else + { + /* 20 bits for the fractional part */ + /* fract is in 12.20 format */ + fract = (x & 0x000FFFFF); + + /* Read two nearest output values from the index */ + y0 = pYData[index]; + y1 = pYData[index + 1]; + + /* Calculation of y0 * (1-fract) and y is in 13.35 format */ + y = ((q63_t) y0 * (0xFFFFF - fract)); + + /* Calculation of (y0 * (1-fract) + y1 * fract) and y is in 13.35 format */ + y += ((q63_t) y1 * (fract)); + + /* convert y to 1.15 format */ + return (q15_t) (y >> 20); + } + } + + + /** + * + * @brief Process function for the Q7 Linear Interpolation Function. + * @param[in] pYData pointer to Q7 Linear Interpolation table + * @param[in] x input sample to process + * @param[in] nValues number of table values + * @return y processed output sample. + * + * \par + * Input sample x is in 12.20 format which contains 12 bits for table index and 20 bits for fractional part. + * This function can support maximum of table size 2^12. + */ + CMSIS_INLINE __STATIC_INLINE q7_t arm_linear_interp_q7( + q7_t * pYData, + q31_t x, + uint32_t nValues) + { + q31_t y; /* output */ + q7_t y0, y1; /* Nearest output values */ + q31_t fract; /* fractional part */ + uint32_t index; /* Index to read nearest output values */ + + /* Input is in 12.20 format */ + /* 12 bits for the table index */ + /* Index value calculation */ + if (x < 0) + { + return (pYData[0]); + } + index = (x >> 20) & 0xfff; + + if (index >= (nValues - 1)) + { + return (pYData[nValues - 1]); + } + else + { + /* 20 bits for the fractional part */ + /* fract is in 12.20 format */ + fract = (x & 0x000FFFFF); + + /* Read two nearest output values from the index and are in 1.7(q7) format */ + y0 = pYData[index]; + y1 = pYData[index + 1]; + + /* Calculation of y0 * (1-fract ) and y is in 13.27(q27) format */ + y = ((y0 * (0xFFFFF - fract))); + + /* Calculation of y1 * fract + y0 * (1-fract) and y is in 13.27(q27) format */ + y += (y1 * fract); + + /* convert y to 1.7(q7) format */ + return (q7_t) (y >> 20); + } + } + + /** + * @} end of LinearInterpolate group + */ + + /** + * @brief Fast approximation to the trigonometric sine function for floating-point data. + * @param[in] x input value in radians. + * @return sin(x). + */ + float32_t arm_sin_f32( + float32_t x); + + + /** + * @brief Fast approximation to the trigonometric sine function for Q31 data. + * @param[in] x Scaled input value in radians. + * @return sin(x). + */ + q31_t arm_sin_q31( + q31_t x); + + + /** + * @brief Fast approximation to the trigonometric sine function for Q15 data. + * @param[in] x Scaled input value in radians. + * @return sin(x). + */ + q15_t arm_sin_q15( + q15_t x); + + + /** + * @brief Fast approximation to the trigonometric cosine function for floating-point data. + * @param[in] x input value in radians. + * @return cos(x). + */ + float32_t arm_cos_f32( + float32_t x); + + + /** + * @brief Fast approximation to the trigonometric cosine function for Q31 data. + * @param[in] x Scaled input value in radians. + * @return cos(x). + */ + q31_t arm_cos_q31( + q31_t x); + + + /** + * @brief Fast approximation to the trigonometric cosine function for Q15 data. + * @param[in] x Scaled input value in radians. + * @return cos(x). + */ + q15_t arm_cos_q15( + q15_t x); + + + /** + * @ingroup groupFastMath + */ + + + /** + * @defgroup SQRT Square Root + * + * Computes the square root of a number. + * There are separate functions for Q15, Q31, and floating-point data types. + * The square root function is computed using the Newton-Raphson algorithm. + * This is an iterative algorithm of the form: + *
    +   *      x1 = x0 - f(x0)/f'(x0)
    +   * 
    + * where x1 is the current estimate, + * x0 is the previous estimate, and + * f'(x0) is the derivative of f() evaluated at x0. + * For the square root function, the algorithm reduces to: + *
    +   *     x0 = in/2                         [initial guess]
    +   *     x1 = 1/2 * ( x0 + in / x0)        [each iteration]
    +   * 
    + */ + + + /** + * @addtogroup SQRT + * @{ + */ + + /** + * @brief Floating-point square root function. + * @param[in] in input value. + * @param[out] pOut square root of input value. + * @return The function returns ARM_MATH_SUCCESS if input value is positive value or ARM_MATH_ARGUMENT_ERROR if + * in is negative value and returns zero output for negative values. + */ + CMSIS_INLINE __STATIC_INLINE arm_status arm_sqrt_f32( + float32_t in, + float32_t * pOut) + { + if (in >= 0.0f) + { + +#if (__FPU_USED == 1) && defined ( __CC_ARM ) + *pOut = __sqrtf(in); +#elif (__FPU_USED == 1) && (defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)) + *pOut = __builtin_sqrtf(in); +#elif (__FPU_USED == 1) && defined(__GNUC__) + *pOut = __builtin_sqrtf(in); +#elif (__FPU_USED == 1) && defined ( __ICCARM__ ) && (__VER__ >= 6040000) + __ASM("VSQRT.F32 %0,%1" : "=t"(*pOut) : "t"(in)); +#else + *pOut = sqrtf(in); +#endif + + return (ARM_MATH_SUCCESS); + } + else + { + *pOut = 0.0f; + return (ARM_MATH_ARGUMENT_ERROR); + } + } + + + /** + * @brief Q31 square root function. + * @param[in] in input value. The range of the input value is [0 +1) or 0x00000000 to 0x7FFFFFFF. + * @param[out] pOut square root of input value. + * @return The function returns ARM_MATH_SUCCESS if input value is positive value or ARM_MATH_ARGUMENT_ERROR if + * in is negative value and returns zero output for negative values. + */ + arm_status arm_sqrt_q31( + q31_t in, + q31_t * pOut); + + + /** + * @brief Q15 square root function. + * @param[in] in input value. The range of the input value is [0 +1) or 0x0000 to 0x7FFF. + * @param[out] pOut square root of input value. + * @return The function returns ARM_MATH_SUCCESS if input value is positive value or ARM_MATH_ARGUMENT_ERROR if + * in is negative value and returns zero output for negative values. + */ + arm_status arm_sqrt_q15( + q15_t in, + q15_t * pOut); + + /** + * @} end of SQRT group + */ + + + /** + * @brief floating-point Circular write function. + */ + CMSIS_INLINE __STATIC_INLINE void arm_circularWrite_f32( + int32_t * circBuffer, + int32_t L, + uint16_t * writeOffset, + int32_t bufferInc, + const int32_t * src, + int32_t srcInc, + uint32_t blockSize) + { + uint32_t i = 0U; + int32_t wOffset; + + /* Copy the value of Index pointer that points + * to the current location where the input samples to be copied */ + wOffset = *writeOffset; + + /* Loop over the blockSize */ + i = blockSize; + + while (i > 0U) + { + /* copy the input sample to the circular buffer */ + circBuffer[wOffset] = *src; + + /* Update the input pointer */ + src += srcInc; + + /* Circularly update wOffset. Watch out for positive and negative value */ + wOffset += bufferInc; + if (wOffset >= L) + wOffset -= L; + + /* Decrement the loop counter */ + i--; + } + + /* Update the index pointer */ + *writeOffset = (uint16_t)wOffset; + } + + + + /** + * @brief floating-point Circular Read function. + */ + CMSIS_INLINE __STATIC_INLINE void arm_circularRead_f32( + int32_t * circBuffer, + int32_t L, + int32_t * readOffset, + int32_t bufferInc, + int32_t * dst, + int32_t * dst_base, + int32_t dst_length, + int32_t dstInc, + uint32_t blockSize) + { + uint32_t i = 0U; + int32_t rOffset, dst_end; + + /* Copy the value of Index pointer that points + * to the current location from where the input samples to be read */ + rOffset = *readOffset; + dst_end = (int32_t) (dst_base + dst_length); + + /* Loop over the blockSize */ + i = blockSize; + + while (i > 0U) + { + /* copy the sample from the circular buffer to the destination buffer */ + *dst = circBuffer[rOffset]; + + /* Update the input pointer */ + dst += dstInc; + + if (dst == (int32_t *) dst_end) + { + dst = dst_base; + } + + /* Circularly update rOffset. Watch out for positive and negative value */ + rOffset += bufferInc; + + if (rOffset >= L) + { + rOffset -= L; + } + + /* Decrement the loop counter */ + i--; + } + + /* Update the index pointer */ + *readOffset = rOffset; + } + + + /** + * @brief Q15 Circular write function. + */ + CMSIS_INLINE __STATIC_INLINE void arm_circularWrite_q15( + q15_t * circBuffer, + int32_t L, + uint16_t * writeOffset, + int32_t bufferInc, + const q15_t * src, + int32_t srcInc, + uint32_t blockSize) + { + uint32_t i = 0U; + int32_t wOffset; + + /* Copy the value of Index pointer that points + * to the current location where the input samples to be copied */ + wOffset = *writeOffset; + + /* Loop over the blockSize */ + i = blockSize; + + while (i > 0U) + { + /* copy the input sample to the circular buffer */ + circBuffer[wOffset] = *src; + + /* Update the input pointer */ + src += srcInc; + + /* Circularly update wOffset. Watch out for positive and negative value */ + wOffset += bufferInc; + if (wOffset >= L) + wOffset -= L; + + /* Decrement the loop counter */ + i--; + } + + /* Update the index pointer */ + *writeOffset = (uint16_t)wOffset; + } + + + /** + * @brief Q15 Circular Read function. + */ + CMSIS_INLINE __STATIC_INLINE void arm_circularRead_q15( + q15_t * circBuffer, + int32_t L, + int32_t * readOffset, + int32_t bufferInc, + q15_t * dst, + q15_t * dst_base, + int32_t dst_length, + int32_t dstInc, + uint32_t blockSize) + { + uint32_t i = 0; + int32_t rOffset, dst_end; + + /* Copy the value of Index pointer that points + * to the current location from where the input samples to be read */ + rOffset = *readOffset; + + dst_end = (int32_t) (dst_base + dst_length); + + /* Loop over the blockSize */ + i = blockSize; + + while (i > 0U) + { + /* copy the sample from the circular buffer to the destination buffer */ + *dst = circBuffer[rOffset]; + + /* Update the input pointer */ + dst += dstInc; + + if (dst == (q15_t *) dst_end) + { + dst = dst_base; + } + + /* Circularly update wOffset. Watch out for positive and negative value */ + rOffset += bufferInc; + + if (rOffset >= L) + { + rOffset -= L; + } + + /* Decrement the loop counter */ + i--; + } + + /* Update the index pointer */ + *readOffset = rOffset; + } + + + /** + * @brief Q7 Circular write function. + */ + CMSIS_INLINE __STATIC_INLINE void arm_circularWrite_q7( + q7_t * circBuffer, + int32_t L, + uint16_t * writeOffset, + int32_t bufferInc, + const q7_t * src, + int32_t srcInc, + uint32_t blockSize) + { + uint32_t i = 0U; + int32_t wOffset; + + /* Copy the value of Index pointer that points + * to the current location where the input samples to be copied */ + wOffset = *writeOffset; + + /* Loop over the blockSize */ + i = blockSize; + + while (i > 0U) + { + /* copy the input sample to the circular buffer */ + circBuffer[wOffset] = *src; + + /* Update the input pointer */ + src += srcInc; + + /* Circularly update wOffset. Watch out for positive and negative value */ + wOffset += bufferInc; + if (wOffset >= L) + wOffset -= L; + + /* Decrement the loop counter */ + i--; + } + + /* Update the index pointer */ + *writeOffset = (uint16_t)wOffset; + } + + + /** + * @brief Q7 Circular Read function. + */ + CMSIS_INLINE __STATIC_INLINE void arm_circularRead_q7( + q7_t * circBuffer, + int32_t L, + int32_t * readOffset, + int32_t bufferInc, + q7_t * dst, + q7_t * dst_base, + int32_t dst_length, + int32_t dstInc, + uint32_t blockSize) + { + uint32_t i = 0; + int32_t rOffset, dst_end; + + /* Copy the value of Index pointer that points + * to the current location from where the input samples to be read */ + rOffset = *readOffset; + + dst_end = (int32_t) (dst_base + dst_length); + + /* Loop over the blockSize */ + i = blockSize; + + while (i > 0U) + { + /* copy the sample from the circular buffer to the destination buffer */ + *dst = circBuffer[rOffset]; + + /* Update the input pointer */ + dst += dstInc; + + if (dst == (q7_t *) dst_end) + { + dst = dst_base; + } + + /* Circularly update rOffset. Watch out for positive and negative value */ + rOffset += bufferInc; + + if (rOffset >= L) + { + rOffset -= L; + } + + /* Decrement the loop counter */ + i--; + } + + /* Update the index pointer */ + *readOffset = rOffset; + } + + + /** + * @brief Sum of the squares of the elements of a Q31 vector. + * @param[in] pSrc is input pointer + * @param[in] blockSize is the number of samples to process + * @param[out] pResult is output value. + */ + void arm_power_q31( + q31_t * pSrc, + uint32_t blockSize, + q63_t * pResult); + + + /** + * @brief Sum of the squares of the elements of a floating-point vector. + * @param[in] pSrc is input pointer + * @param[in] blockSize is the number of samples to process + * @param[out] pResult is output value. + */ + void arm_power_f32( + float32_t * pSrc, + uint32_t blockSize, + float32_t * pResult); + + + /** + * @brief Sum of the squares of the elements of a Q15 vector. + * @param[in] pSrc is input pointer + * @param[in] blockSize is the number of samples to process + * @param[out] pResult is output value. + */ + void arm_power_q15( + q15_t * pSrc, + uint32_t blockSize, + q63_t * pResult); + + + /** + * @brief Sum of the squares of the elements of a Q7 vector. + * @param[in] pSrc is input pointer + * @param[in] blockSize is the number of samples to process + * @param[out] pResult is output value. + */ + void arm_power_q7( + q7_t * pSrc, + uint32_t blockSize, + q31_t * pResult); + + + /** + * @brief Mean value of a Q7 vector. + * @param[in] pSrc is input pointer + * @param[in] blockSize is the number of samples to process + * @param[out] pResult is output value. + */ + void arm_mean_q7( + q7_t * pSrc, + uint32_t blockSize, + q7_t * pResult); + + + /** + * @brief Mean value of a Q15 vector. + * @param[in] pSrc is input pointer + * @param[in] blockSize is the number of samples to process + * @param[out] pResult is output value. + */ + void arm_mean_q15( + q15_t * pSrc, + uint32_t blockSize, + q15_t * pResult); + + + /** + * @brief Mean value of a Q31 vector. + * @param[in] pSrc is input pointer + * @param[in] blockSize is the number of samples to process + * @param[out] pResult is output value. + */ + void arm_mean_q31( + q31_t * pSrc, + uint32_t blockSize, + q31_t * pResult); + + + /** + * @brief Mean value of a floating-point vector. + * @param[in] pSrc is input pointer + * @param[in] blockSize is the number of samples to process + * @param[out] pResult is output value. + */ + void arm_mean_f32( + float32_t * pSrc, + uint32_t blockSize, + float32_t * pResult); + + + /** + * @brief Variance of the elements of a floating-point vector. + * @param[in] pSrc is input pointer + * @param[in] blockSize is the number of samples to process + * @param[out] pResult is output value. + */ + void arm_var_f32( + float32_t * pSrc, + uint32_t blockSize, + float32_t * pResult); + + + /** + * @brief Variance of the elements of a Q31 vector. + * @param[in] pSrc is input pointer + * @param[in] blockSize is the number of samples to process + * @param[out] pResult is output value. + */ + void arm_var_q31( + q31_t * pSrc, + uint32_t blockSize, + q31_t * pResult); + + + /** + * @brief Variance of the elements of a Q15 vector. + * @param[in] pSrc is input pointer + * @param[in] blockSize is the number of samples to process + * @param[out] pResult is output value. + */ + void arm_var_q15( + q15_t * pSrc, + uint32_t blockSize, + q15_t * pResult); + + + /** + * @brief Root Mean Square of the elements of a floating-point vector. + * @param[in] pSrc is input pointer + * @param[in] blockSize is the number of samples to process + * @param[out] pResult is output value. + */ + void arm_rms_f32( + float32_t * pSrc, + uint32_t blockSize, + float32_t * pResult); + + + /** + * @brief Root Mean Square of the elements of a Q31 vector. + * @param[in] pSrc is input pointer + * @param[in] blockSize is the number of samples to process + * @param[out] pResult is output value. + */ + void arm_rms_q31( + q31_t * pSrc, + uint32_t blockSize, + q31_t * pResult); + + + /** + * @brief Root Mean Square of the elements of a Q15 vector. + * @param[in] pSrc is input pointer + * @param[in] blockSize is the number of samples to process + * @param[out] pResult is output value. + */ + void arm_rms_q15( + q15_t * pSrc, + uint32_t blockSize, + q15_t * pResult); + + + /** + * @brief Standard deviation of the elements of a floating-point vector. + * @param[in] pSrc is input pointer + * @param[in] blockSize is the number of samples to process + * @param[out] pResult is output value. + */ + void arm_std_f32( + float32_t * pSrc, + uint32_t blockSize, + float32_t * pResult); + + + /** + * @brief Standard deviation of the elements of a Q31 vector. + * @param[in] pSrc is input pointer + * @param[in] blockSize is the number of samples to process + * @param[out] pResult is output value. + */ + void arm_std_q31( + q31_t * pSrc, + uint32_t blockSize, + q31_t * pResult); + + + /** + * @brief Standard deviation of the elements of a Q15 vector. + * @param[in] pSrc is input pointer + * @param[in] blockSize is the number of samples to process + * @param[out] pResult is output value. + */ + void arm_std_q15( + q15_t * pSrc, + uint32_t blockSize, + q15_t * pResult); + + + /** + * @brief Floating-point complex magnitude + * @param[in] pSrc points to the complex input vector + * @param[out] pDst points to the real output vector + * @param[in] numSamples number of complex samples in the input vector + */ + void arm_cmplx_mag_f32( + float32_t * pSrc, + float32_t * pDst, + uint32_t numSamples); + + + /** + * @brief Q31 complex magnitude + * @param[in] pSrc points to the complex input vector + * @param[out] pDst points to the real output vector + * @param[in] numSamples number of complex samples in the input vector + */ + void arm_cmplx_mag_q31( + q31_t * pSrc, + q31_t * pDst, + uint32_t numSamples); + + + /** + * @brief Q15 complex magnitude + * @param[in] pSrc points to the complex input vector + * @param[out] pDst points to the real output vector + * @param[in] numSamples number of complex samples in the input vector + */ + void arm_cmplx_mag_q15( + q15_t * pSrc, + q15_t * pDst, + uint32_t numSamples); + + + /** + * @brief Q15 complex dot product + * @param[in] pSrcA points to the first input vector + * @param[in] pSrcB points to the second input vector + * @param[in] numSamples number of complex samples in each vector + * @param[out] realResult real part of the result returned here + * @param[out] imagResult imaginary part of the result returned here + */ + void arm_cmplx_dot_prod_q15( + q15_t * pSrcA, + q15_t * pSrcB, + uint32_t numSamples, + q31_t * realResult, + q31_t * imagResult); + + + /** + * @brief Q31 complex dot product + * @param[in] pSrcA points to the first input vector + * @param[in] pSrcB points to the second input vector + * @param[in] numSamples number of complex samples in each vector + * @param[out] realResult real part of the result returned here + * @param[out] imagResult imaginary part of the result returned here + */ + void arm_cmplx_dot_prod_q31( + q31_t * pSrcA, + q31_t * pSrcB, + uint32_t numSamples, + q63_t * realResult, + q63_t * imagResult); + + + /** + * @brief Floating-point complex dot product + * @param[in] pSrcA points to the first input vector + * @param[in] pSrcB points to the second input vector + * @param[in] numSamples number of complex samples in each vector + * @param[out] realResult real part of the result returned here + * @param[out] imagResult imaginary part of the result returned here + */ + void arm_cmplx_dot_prod_f32( + float32_t * pSrcA, + float32_t * pSrcB, + uint32_t numSamples, + float32_t * realResult, + float32_t * imagResult); + + + /** + * @brief Q15 complex-by-real multiplication + * @param[in] pSrcCmplx points to the complex input vector + * @param[in] pSrcReal points to the real input vector + * @param[out] pCmplxDst points to the complex output vector + * @param[in] numSamples number of samples in each vector + */ + void arm_cmplx_mult_real_q15( + q15_t * pSrcCmplx, + q15_t * pSrcReal, + q15_t * pCmplxDst, + uint32_t numSamples); + + + /** + * @brief Q31 complex-by-real multiplication + * @param[in] pSrcCmplx points to the complex input vector + * @param[in] pSrcReal points to the real input vector + * @param[out] pCmplxDst points to the complex output vector + * @param[in] numSamples number of samples in each vector + */ + void arm_cmplx_mult_real_q31( + q31_t * pSrcCmplx, + q31_t * pSrcReal, + q31_t * pCmplxDst, + uint32_t numSamples); + + + /** + * @brief Floating-point complex-by-real multiplication + * @param[in] pSrcCmplx points to the complex input vector + * @param[in] pSrcReal points to the real input vector + * @param[out] pCmplxDst points to the complex output vector + * @param[in] numSamples number of samples in each vector + */ + void arm_cmplx_mult_real_f32( + float32_t * pSrcCmplx, + float32_t * pSrcReal, + float32_t * pCmplxDst, + uint32_t numSamples); + + + /** + * @brief Minimum value of a Q7 vector. + * @param[in] pSrc is input pointer + * @param[in] blockSize is the number of samples to process + * @param[out] result is output pointer + * @param[in] index is the array index of the minimum value in the input buffer. + */ + void arm_min_q7( + q7_t * pSrc, + uint32_t blockSize, + q7_t * result, + uint32_t * index); + + + /** + * @brief Minimum value of a Q15 vector. + * @param[in] pSrc is input pointer + * @param[in] blockSize is the number of samples to process + * @param[out] pResult is output pointer + * @param[in] pIndex is the array index of the minimum value in the input buffer. + */ + void arm_min_q15( + q15_t * pSrc, + uint32_t blockSize, + q15_t * pResult, + uint32_t * pIndex); + + + /** + * @brief Minimum value of a Q31 vector. + * @param[in] pSrc is input pointer + * @param[in] blockSize is the number of samples to process + * @param[out] pResult is output pointer + * @param[out] pIndex is the array index of the minimum value in the input buffer. + */ + void arm_min_q31( + q31_t * pSrc, + uint32_t blockSize, + q31_t * pResult, + uint32_t * pIndex); + + + /** + * @brief Minimum value of a floating-point vector. + * @param[in] pSrc is input pointer + * @param[in] blockSize is the number of samples to process + * @param[out] pResult is output pointer + * @param[out] pIndex is the array index of the minimum value in the input buffer. + */ + void arm_min_f32( + float32_t * pSrc, + uint32_t blockSize, + float32_t * pResult, + uint32_t * pIndex); + + +/** + * @brief Maximum value of a Q7 vector. + * @param[in] pSrc points to the input buffer + * @param[in] blockSize length of the input vector + * @param[out] pResult maximum value returned here + * @param[out] pIndex index of maximum value returned here + */ + void arm_max_q7( + q7_t * pSrc, + uint32_t blockSize, + q7_t * pResult, + uint32_t * pIndex); + + +/** + * @brief Maximum value of a Q15 vector. + * @param[in] pSrc points to the input buffer + * @param[in] blockSize length of the input vector + * @param[out] pResult maximum value returned here + * @param[out] pIndex index of maximum value returned here + */ + void arm_max_q15( + q15_t * pSrc, + uint32_t blockSize, + q15_t * pResult, + uint32_t * pIndex); + + +/** + * @brief Maximum value of a Q31 vector. + * @param[in] pSrc points to the input buffer + * @param[in] blockSize length of the input vector + * @param[out] pResult maximum value returned here + * @param[out] pIndex index of maximum value returned here + */ + void arm_max_q31( + q31_t * pSrc, + uint32_t blockSize, + q31_t * pResult, + uint32_t * pIndex); + + +/** + * @brief Maximum value of a floating-point vector. + * @param[in] pSrc points to the input buffer + * @param[in] blockSize length of the input vector + * @param[out] pResult maximum value returned here + * @param[out] pIndex index of maximum value returned here + */ + void arm_max_f32( + float32_t * pSrc, + uint32_t blockSize, + float32_t * pResult, + uint32_t * pIndex); + + + /** + * @brief Q15 complex-by-complex multiplication + * @param[in] pSrcA points to the first input vector + * @param[in] pSrcB points to the second input vector + * @param[out] pDst points to the output vector + * @param[in] numSamples number of complex samples in each vector + */ + void arm_cmplx_mult_cmplx_q15( + q15_t * pSrcA, + q15_t * pSrcB, + q15_t * pDst, + uint32_t numSamples); + + + /** + * @brief Q31 complex-by-complex multiplication + * @param[in] pSrcA points to the first input vector + * @param[in] pSrcB points to the second input vector + * @param[out] pDst points to the output vector + * @param[in] numSamples number of complex samples in each vector + */ + void arm_cmplx_mult_cmplx_q31( + q31_t * pSrcA, + q31_t * pSrcB, + q31_t * pDst, + uint32_t numSamples); + + + /** + * @brief Floating-point complex-by-complex multiplication + * @param[in] pSrcA points to the first input vector + * @param[in] pSrcB points to the second input vector + * @param[out] pDst points to the output vector + * @param[in] numSamples number of complex samples in each vector + */ + void arm_cmplx_mult_cmplx_f32( + float32_t * pSrcA, + float32_t * pSrcB, + float32_t * pDst, + uint32_t numSamples); + + + /** + * @brief Converts the elements of the floating-point vector to Q31 vector. + * @param[in] pSrc points to the floating-point input vector + * @param[out] pDst points to the Q31 output vector + * @param[in] blockSize length of the input vector + */ + void arm_float_to_q31( + float32_t * pSrc, + q31_t * pDst, + uint32_t blockSize); + + + /** + * @brief Converts the elements of the floating-point vector to Q15 vector. + * @param[in] pSrc points to the floating-point input vector + * @param[out] pDst points to the Q15 output vector + * @param[in] blockSize length of the input vector + */ + void arm_float_to_q15( + float32_t * pSrc, + q15_t * pDst, + uint32_t blockSize); + + + /** + * @brief Converts the elements of the floating-point vector to Q7 vector. + * @param[in] pSrc points to the floating-point input vector + * @param[out] pDst points to the Q7 output vector + * @param[in] blockSize length of the input vector + */ + void arm_float_to_q7( + float32_t * pSrc, + q7_t * pDst, + uint32_t blockSize); + + + /** + * @brief Converts the elements of the Q31 vector to Q15 vector. + * @param[in] pSrc is input pointer + * @param[out] pDst is output pointer + * @param[in] blockSize is the number of samples to process + */ + void arm_q31_to_q15( + q31_t * pSrc, + q15_t * pDst, + uint32_t blockSize); + + + /** + * @brief Converts the elements of the Q31 vector to Q7 vector. + * @param[in] pSrc is input pointer + * @param[out] pDst is output pointer + * @param[in] blockSize is the number of samples to process + */ + void arm_q31_to_q7( + q31_t * pSrc, + q7_t * pDst, + uint32_t blockSize); + + + /** + * @brief Converts the elements of the Q15 vector to floating-point vector. + * @param[in] pSrc is input pointer + * @param[out] pDst is output pointer + * @param[in] blockSize is the number of samples to process + */ + void arm_q15_to_float( + q15_t * pSrc, + float32_t * pDst, + uint32_t blockSize); + + + /** + * @brief Converts the elements of the Q15 vector to Q31 vector. + * @param[in] pSrc is input pointer + * @param[out] pDst is output pointer + * @param[in] blockSize is the number of samples to process + */ + void arm_q15_to_q31( + q15_t * pSrc, + q31_t * pDst, + uint32_t blockSize); + + + /** + * @brief Converts the elements of the Q15 vector to Q7 vector. + * @param[in] pSrc is input pointer + * @param[out] pDst is output pointer + * @param[in] blockSize is the number of samples to process + */ + void arm_q15_to_q7( + q15_t * pSrc, + q7_t * pDst, + uint32_t blockSize); + + + /** + * @ingroup groupInterpolation + */ + + /** + * @defgroup BilinearInterpolate Bilinear Interpolation + * + * Bilinear interpolation is an extension of linear interpolation applied to a two dimensional grid. + * The underlying function f(x, y) is sampled on a regular grid and the interpolation process + * determines values between the grid points. + * Bilinear interpolation is equivalent to two step linear interpolation, first in the x-dimension and then in the y-dimension. + * Bilinear interpolation is often used in image processing to rescale images. + * The CMSIS DSP library provides bilinear interpolation functions for Q7, Q15, Q31, and floating-point data types. + * + * Algorithm + * \par + * The instance structure used by the bilinear interpolation functions describes a two dimensional data table. + * For floating-point, the instance structure is defined as: + *
    +   *   typedef struct
    +   *   {
    +   *     uint16_t numRows;
    +   *     uint16_t numCols;
    +   *     float32_t *pData;
    +   * } arm_bilinear_interp_instance_f32;
    +   * 
    + * + * \par + * where numRows specifies the number of rows in the table; + * numCols specifies the number of columns in the table; + * and pData points to an array of size numRows*numCols values. + * The data table pTable is organized in row order and the supplied data values fall on integer indexes. + * That is, table element (x,y) is located at pTable[x + y*numCols] where x and y are integers. + * + * \par + * Let (x, y) specify the desired interpolation point. Then define: + *
    +   *     XF = floor(x)
    +   *     YF = floor(y)
    +   * 
    + * \par + * The interpolated output point is computed as: + *
    +   *  f(x, y) = f(XF, YF) * (1-(x-XF)) * (1-(y-YF))
    +   *           + f(XF+1, YF) * (x-XF)*(1-(y-YF))
    +   *           + f(XF, YF+1) * (1-(x-XF))*(y-YF)
    +   *           + f(XF+1, YF+1) * (x-XF)*(y-YF)
    +   * 
    + * Note that the coordinates (x, y) contain integer and fractional components. + * The integer components specify which portion of the table to use while the + * fractional components control the interpolation processor. + * + * \par + * if (x,y) are outside of the table boundary, Bilinear interpolation returns zero output. + */ + + /** + * @addtogroup BilinearInterpolate + * @{ + */ + + + /** + * + * @brief Floating-point bilinear interpolation. + * @param[in,out] S points to an instance of the interpolation structure. + * @param[in] X interpolation coordinate. + * @param[in] Y interpolation coordinate. + * @return out interpolated value. + */ + CMSIS_INLINE __STATIC_INLINE float32_t arm_bilinear_interp_f32( + const arm_bilinear_interp_instance_f32 * S, + float32_t X, + float32_t Y) + { + float32_t out; + float32_t f00, f01, f10, f11; + float32_t *pData = S->pData; + int32_t xIndex, yIndex, index; + float32_t xdiff, ydiff; + float32_t b1, b2, b3, b4; + + xIndex = (int32_t) X; + yIndex = (int32_t) Y; + + /* Care taken for table outside boundary */ + /* Returns zero output when values are outside table boundary */ + if (xIndex < 0 || xIndex > (S->numRows - 1) || yIndex < 0 || yIndex > (S->numCols - 1)) + { + return (0); + } + + /* Calculation of index for two nearest points in X-direction */ + index = (xIndex - 1) + (yIndex - 1) * S->numCols; + + + /* Read two nearest points in X-direction */ + f00 = pData[index]; + f01 = pData[index + 1]; + + /* Calculation of index for two nearest points in Y-direction */ + index = (xIndex - 1) + (yIndex) * S->numCols; + + + /* Read two nearest points in Y-direction */ + f10 = pData[index]; + f11 = pData[index + 1]; + + /* Calculation of intermediate values */ + b1 = f00; + b2 = f01 - f00; + b3 = f10 - f00; + b4 = f00 - f01 - f10 + f11; + + /* Calculation of fractional part in X */ + xdiff = X - xIndex; + + /* Calculation of fractional part in Y */ + ydiff = Y - yIndex; + + /* Calculation of bi-linear interpolated output */ + out = b1 + b2 * xdiff + b3 * ydiff + b4 * xdiff * ydiff; + + /* return to application */ + return (out); + } + + + /** + * + * @brief Q31 bilinear interpolation. + * @param[in,out] S points to an instance of the interpolation structure. + * @param[in] X interpolation coordinate in 12.20 format. + * @param[in] Y interpolation coordinate in 12.20 format. + * @return out interpolated value. + */ + CMSIS_INLINE __STATIC_INLINE q31_t arm_bilinear_interp_q31( + arm_bilinear_interp_instance_q31 * S, + q31_t X, + q31_t Y) + { + q31_t out; /* Temporary output */ + q31_t acc = 0; /* output */ + q31_t xfract, yfract; /* X, Y fractional parts */ + q31_t x1, x2, y1, y2; /* Nearest output values */ + int32_t rI, cI; /* Row and column indices */ + q31_t *pYData = S->pData; /* pointer to output table values */ + uint32_t nCols = S->numCols; /* num of rows */ + + /* Input is in 12.20 format */ + /* 12 bits for the table index */ + /* Index value calculation */ + rI = ((X & (q31_t)0xFFF00000) >> 20); + + /* Input is in 12.20 format */ + /* 12 bits for the table index */ + /* Index value calculation */ + cI = ((Y & (q31_t)0xFFF00000) >> 20); + + /* Care taken for table outside boundary */ + /* Returns zero output when values are outside table boundary */ + if (rI < 0 || rI > (S->numRows - 1) || cI < 0 || cI > (S->numCols - 1)) + { + return (0); + } + + /* 20 bits for the fractional part */ + /* shift left xfract by 11 to keep 1.31 format */ + xfract = (X & 0x000FFFFF) << 11U; + + /* Read two nearest output values from the index */ + x1 = pYData[(rI) + (int32_t)nCols * (cI) ]; + x2 = pYData[(rI) + (int32_t)nCols * (cI) + 1]; + + /* 20 bits for the fractional part */ + /* shift left yfract by 11 to keep 1.31 format */ + yfract = (Y & 0x000FFFFF) << 11U; + + /* Read two nearest output values from the index */ + y1 = pYData[(rI) + (int32_t)nCols * (cI + 1) ]; + y2 = pYData[(rI) + (int32_t)nCols * (cI + 1) + 1]; + + /* Calculation of x1 * (1-xfract ) * (1-yfract) and acc is in 3.29(q29) format */ + out = ((q31_t) (((q63_t) x1 * (0x7FFFFFFF - xfract)) >> 32)); + acc = ((q31_t) (((q63_t) out * (0x7FFFFFFF - yfract)) >> 32)); + + /* x2 * (xfract) * (1-yfract) in 3.29(q29) and adding to acc */ + out = ((q31_t) ((q63_t) x2 * (0x7FFFFFFF - yfract) >> 32)); + acc += ((q31_t) ((q63_t) out * (xfract) >> 32)); + + /* y1 * (1 - xfract) * (yfract) in 3.29(q29) and adding to acc */ + out = ((q31_t) ((q63_t) y1 * (0x7FFFFFFF - xfract) >> 32)); + acc += ((q31_t) ((q63_t) out * (yfract) >> 32)); + + /* y2 * (xfract) * (yfract) in 3.29(q29) and adding to acc */ + out = ((q31_t) ((q63_t) y2 * (xfract) >> 32)); + acc += ((q31_t) ((q63_t) out * (yfract) >> 32)); + + /* Convert acc to 1.31(q31) format */ + return ((q31_t)(acc << 2)); + } + + + /** + * @brief Q15 bilinear interpolation. + * @param[in,out] S points to an instance of the interpolation structure. + * @param[in] X interpolation coordinate in 12.20 format. + * @param[in] Y interpolation coordinate in 12.20 format. + * @return out interpolated value. + */ + CMSIS_INLINE __STATIC_INLINE q15_t arm_bilinear_interp_q15( + arm_bilinear_interp_instance_q15 * S, + q31_t X, + q31_t Y) + { + q63_t acc = 0; /* output */ + q31_t out; /* Temporary output */ + q15_t x1, x2, y1, y2; /* Nearest output values */ + q31_t xfract, yfract; /* X, Y fractional parts */ + int32_t rI, cI; /* Row and column indices */ + q15_t *pYData = S->pData; /* pointer to output table values */ + uint32_t nCols = S->numCols; /* num of rows */ + + /* Input is in 12.20 format */ + /* 12 bits for the table index */ + /* Index value calculation */ + rI = ((X & (q31_t)0xFFF00000) >> 20); + + /* Input is in 12.20 format */ + /* 12 bits for the table index */ + /* Index value calculation */ + cI = ((Y & (q31_t)0xFFF00000) >> 20); + + /* Care taken for table outside boundary */ + /* Returns zero output when values are outside table boundary */ + if (rI < 0 || rI > (S->numRows - 1) || cI < 0 || cI > (S->numCols - 1)) + { + return (0); + } + + /* 20 bits for the fractional part */ + /* xfract should be in 12.20 format */ + xfract = (X & 0x000FFFFF); + + /* Read two nearest output values from the index */ + x1 = pYData[((uint32_t)rI) + nCols * ((uint32_t)cI) ]; + x2 = pYData[((uint32_t)rI) + nCols * ((uint32_t)cI) + 1]; + + /* 20 bits for the fractional part */ + /* yfract should be in 12.20 format */ + yfract = (Y & 0x000FFFFF); + + /* Read two nearest output values from the index */ + y1 = pYData[((uint32_t)rI) + nCols * ((uint32_t)cI + 1) ]; + y2 = pYData[((uint32_t)rI) + nCols * ((uint32_t)cI + 1) + 1]; + + /* Calculation of x1 * (1-xfract ) * (1-yfract) and acc is in 13.51 format */ + + /* x1 is in 1.15(q15), xfract in 12.20 format and out is in 13.35 format */ + /* convert 13.35 to 13.31 by right shifting and out is in 1.31 */ + out = (q31_t) (((q63_t) x1 * (0xFFFFF - xfract)) >> 4U); + acc = ((q63_t) out * (0xFFFFF - yfract)); + + /* x2 * (xfract) * (1-yfract) in 1.51 and adding to acc */ + out = (q31_t) (((q63_t) x2 * (0xFFFFF - yfract)) >> 4U); + acc += ((q63_t) out * (xfract)); + + /* y1 * (1 - xfract) * (yfract) in 1.51 and adding to acc */ + out = (q31_t) (((q63_t) y1 * (0xFFFFF - xfract)) >> 4U); + acc += ((q63_t) out * (yfract)); + + /* y2 * (xfract) * (yfract) in 1.51 and adding to acc */ + out = (q31_t) (((q63_t) y2 * (xfract)) >> 4U); + acc += ((q63_t) out * (yfract)); + + /* acc is in 13.51 format and down shift acc by 36 times */ + /* Convert out to 1.15 format */ + return ((q15_t)(acc >> 36)); + } + + + /** + * @brief Q7 bilinear interpolation. + * @param[in,out] S points to an instance of the interpolation structure. + * @param[in] X interpolation coordinate in 12.20 format. + * @param[in] Y interpolation coordinate in 12.20 format. + * @return out interpolated value. + */ + CMSIS_INLINE __STATIC_INLINE q7_t arm_bilinear_interp_q7( + arm_bilinear_interp_instance_q7 * S, + q31_t X, + q31_t Y) + { + q63_t acc = 0; /* output */ + q31_t out; /* Temporary output */ + q31_t xfract, yfract; /* X, Y fractional parts */ + q7_t x1, x2, y1, y2; /* Nearest output values */ + int32_t rI, cI; /* Row and column indices */ + q7_t *pYData = S->pData; /* pointer to output table values */ + uint32_t nCols = S->numCols; /* num of rows */ + + /* Input is in 12.20 format */ + /* 12 bits for the table index */ + /* Index value calculation */ + rI = ((X & (q31_t)0xFFF00000) >> 20); + + /* Input is in 12.20 format */ + /* 12 bits for the table index */ + /* Index value calculation */ + cI = ((Y & (q31_t)0xFFF00000) >> 20); + + /* Care taken for table outside boundary */ + /* Returns zero output when values are outside table boundary */ + if (rI < 0 || rI > (S->numRows - 1) || cI < 0 || cI > (S->numCols - 1)) + { + return (0); + } + + /* 20 bits for the fractional part */ + /* xfract should be in 12.20 format */ + xfract = (X & (q31_t)0x000FFFFF); + + /* Read two nearest output values from the index */ + x1 = pYData[((uint32_t)rI) + nCols * ((uint32_t)cI) ]; + x2 = pYData[((uint32_t)rI) + nCols * ((uint32_t)cI) + 1]; + + /* 20 bits for the fractional part */ + /* yfract should be in 12.20 format */ + yfract = (Y & (q31_t)0x000FFFFF); + + /* Read two nearest output values from the index */ + y1 = pYData[((uint32_t)rI) + nCols * ((uint32_t)cI + 1) ]; + y2 = pYData[((uint32_t)rI) + nCols * ((uint32_t)cI + 1) + 1]; + + /* Calculation of x1 * (1-xfract ) * (1-yfract) and acc is in 16.47 format */ + out = ((x1 * (0xFFFFF - xfract))); + acc = (((q63_t) out * (0xFFFFF - yfract))); + + /* x2 * (xfract) * (1-yfract) in 2.22 and adding to acc */ + out = ((x2 * (0xFFFFF - yfract))); + acc += (((q63_t) out * (xfract))); + + /* y1 * (1 - xfract) * (yfract) in 2.22 and adding to acc */ + out = ((y1 * (0xFFFFF - xfract))); + acc += (((q63_t) out * (yfract))); + + /* y2 * (xfract) * (yfract) in 2.22 and adding to acc */ + out = ((y2 * (yfract))); + acc += (((q63_t) out * (xfract))); + + /* acc in 16.47 format and down shift by 40 to convert to 1.7 format */ + return ((q7_t)(acc >> 40)); + } + + /** + * @} end of BilinearInterpolate group + */ + + +/* SMMLAR */ +#define multAcc_32x32_keep32_R(a, x, y) \ + a = (q31_t) (((((q63_t) a) << 32) + ((q63_t) x * y) + 0x80000000LL ) >> 32) + +/* SMMLSR */ +#define multSub_32x32_keep32_R(a, x, y) \ + a = (q31_t) (((((q63_t) a) << 32) - ((q63_t) x * y) + 0x80000000LL ) >> 32) + +/* SMMULR */ +#define mult_32x32_keep32_R(a, x, y) \ + a = (q31_t) (((q63_t) x * y + 0x80000000LL ) >> 32) + +/* SMMLA */ +#define multAcc_32x32_keep32(a, x, y) \ + a += (q31_t) (((q63_t) x * y) >> 32) + +/* SMMLS */ +#define multSub_32x32_keep32(a, x, y) \ + a -= (q31_t) (((q63_t) x * y) >> 32) + +/* SMMUL */ +#define mult_32x32_keep32(a, x, y) \ + a = (q31_t) (((q63_t) x * y ) >> 32) + + +#if defined ( __CC_ARM ) + /* Enter low optimization region - place directly above function definition */ + #if defined( ARM_MATH_CM4 ) || defined( ARM_MATH_CM7) + #define LOW_OPTIMIZATION_ENTER \ + _Pragma ("push") \ + _Pragma ("O1") + #else + #define LOW_OPTIMIZATION_ENTER + #endif + + /* Exit low optimization region - place directly after end of function definition */ + #if defined ( ARM_MATH_CM4 ) || defined ( ARM_MATH_CM7 ) + #define LOW_OPTIMIZATION_EXIT \ + _Pragma ("pop") + #else + #define LOW_OPTIMIZATION_EXIT + #endif + + /* Enter low optimization region - place directly above function definition */ + #define IAR_ONLY_LOW_OPTIMIZATION_ENTER + + /* Exit low optimization region - place directly after end of function definition */ + #define IAR_ONLY_LOW_OPTIMIZATION_EXIT + +#elif defined (__ARMCC_VERSION ) && ( __ARMCC_VERSION >= 6010050 ) + #define LOW_OPTIMIZATION_ENTER + #define LOW_OPTIMIZATION_EXIT + #define IAR_ONLY_LOW_OPTIMIZATION_ENTER + #define IAR_ONLY_LOW_OPTIMIZATION_EXIT + +#elif defined ( __GNUC__ ) + #define LOW_OPTIMIZATION_ENTER \ + __attribute__(( optimize("-O1") )) + #define LOW_OPTIMIZATION_EXIT + #define IAR_ONLY_LOW_OPTIMIZATION_ENTER + #define IAR_ONLY_LOW_OPTIMIZATION_EXIT + +#elif defined ( __ICCARM__ ) + /* Enter low optimization region - place directly above function definition */ + #if defined ( ARM_MATH_CM4 ) || defined ( ARM_MATH_CM7 ) + #define LOW_OPTIMIZATION_ENTER \ + _Pragma ("optimize=low") + #else + #define LOW_OPTIMIZATION_ENTER + #endif + + /* Exit low optimization region - place directly after end of function definition */ + #define LOW_OPTIMIZATION_EXIT + + /* Enter low optimization region - place directly above function definition */ + #if defined ( ARM_MATH_CM4 ) || defined ( ARM_MATH_CM7 ) + #define IAR_ONLY_LOW_OPTIMIZATION_ENTER \ + _Pragma ("optimize=low") + #else + #define IAR_ONLY_LOW_OPTIMIZATION_ENTER + #endif + + /* Exit low optimization region - place directly after end of function definition */ + #define IAR_ONLY_LOW_OPTIMIZATION_EXIT + +#elif defined ( __TI_ARM__ ) + #define LOW_OPTIMIZATION_ENTER + #define LOW_OPTIMIZATION_EXIT + #define IAR_ONLY_LOW_OPTIMIZATION_ENTER + #define IAR_ONLY_LOW_OPTIMIZATION_EXIT + +#elif defined ( __CSMC__ ) + #define LOW_OPTIMIZATION_ENTER + #define LOW_OPTIMIZATION_EXIT + #define IAR_ONLY_LOW_OPTIMIZATION_ENTER + #define IAR_ONLY_LOW_OPTIMIZATION_EXIT + +#elif defined ( __TASKING__ ) + #define LOW_OPTIMIZATION_ENTER + #define LOW_OPTIMIZATION_EXIT + #define IAR_ONLY_LOW_OPTIMIZATION_ENTER + #define IAR_ONLY_LOW_OPTIMIZATION_EXIT + +#endif + + +#ifdef __cplusplus +} +#endif + +/* Compiler specific diagnostic adjustment */ +#if defined ( __CC_ARM ) + +#elif defined ( __ARMCC_VERSION ) && ( __ARMCC_VERSION >= 6010050 ) + +#elif defined ( __GNUC__ ) +#pragma GCC diagnostic pop + +#elif defined ( __ICCARM__ ) + +#elif defined ( __TI_ARM__ ) + +#elif defined ( __CSMC__ ) + +#elif defined ( __TASKING__ ) + +#else + #error Unknown compiler +#endif + +#endif /* _ARM_MATH_H */ + +/** + * + * End of file. + */ diff --git a/src/boards/mcu/samr34/ASF/thirdparty/CMSIS/Include/cmsis_compiler.h b/src/boards/mcu/samr34/ASF/thirdparty/CMSIS/Include/cmsis_compiler.h new file mode 100644 index 000000000..79a2cac36 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/thirdparty/CMSIS/Include/cmsis_compiler.h @@ -0,0 +1,266 @@ +/**************************************************************************//** + * @file cmsis_compiler.h + * @brief CMSIS compiler generic header file + * @version V5.0.4 + * @date 10. January 2018 + ******************************************************************************/ +/* + * Copyright (c) 2009-2018 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __CMSIS_COMPILER_H +#define __CMSIS_COMPILER_H + +#include + +/* + * Arm Compiler 4/5 + */ +#if defined ( __CC_ARM ) + #include "cmsis_armcc.h" + + +/* + * Arm Compiler 6 (armclang) + */ +#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #include "cmsis_armclang.h" + + +/* + * GNU Compiler + */ +#elif defined ( __GNUC__ ) + #include "cmsis_gcc.h" + + +/* + * IAR Compiler + */ +#elif defined ( __ICCARM__ ) + #include + + +/* + * TI Arm Compiler + */ +#elif defined ( __TI_ARM__ ) + #include + + #ifndef __ASM + #define __ASM __asm + #endif + #ifndef __INLINE + #define __INLINE inline + #endif + #ifndef __STATIC_INLINE + #define __STATIC_INLINE static inline + #endif + #ifndef __STATIC_FORCEINLINE + #define __STATIC_FORCEINLINE __STATIC_INLINE + #endif + #ifndef __NO_RETURN + #define __NO_RETURN __attribute__((noreturn)) + #endif + #ifndef __USED + #define __USED __attribute__((used)) + #endif + #ifndef __WEAK + #define __WEAK __attribute__((weak)) + #endif + #ifndef __PACKED + #define __PACKED __attribute__((packed)) + #endif + #ifndef __PACKED_STRUCT + #define __PACKED_STRUCT struct __attribute__((packed)) + #endif + #ifndef __PACKED_UNION + #define __PACKED_UNION union __attribute__((packed)) + #endif + #ifndef __UNALIGNED_UINT32 /* deprecated */ + struct __attribute__((packed)) T_UINT32 { uint32_t v; }; + #define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v) + #endif + #ifndef __UNALIGNED_UINT16_WRITE + __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; }; + #define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void*)(addr))->v) = (val)) + #endif + #ifndef __UNALIGNED_UINT16_READ + __PACKED_STRUCT T_UINT16_READ { uint16_t v; }; + #define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v) + #endif + #ifndef __UNALIGNED_UINT32_WRITE + __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; }; + #define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val)) + #endif + #ifndef __UNALIGNED_UINT32_READ + __PACKED_STRUCT T_UINT32_READ { uint32_t v; }; + #define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v) + #endif + #ifndef __ALIGNED + #define __ALIGNED(x) __attribute__((aligned(x))) + #endif + #ifndef __RESTRICT + #warning No compiler specific solution for __RESTRICT. __RESTRICT is ignored. + #define __RESTRICT + #endif + + +/* + * TASKING Compiler + */ +#elif defined ( __TASKING__ ) + /* + * The CMSIS functions have been implemented as intrinsics in the compiler. + * Please use "carm -?i" to get an up to date list of all intrinsics, + * Including the CMSIS ones. + */ + + #ifndef __ASM + #define __ASM __asm + #endif + #ifndef __INLINE + #define __INLINE inline + #endif + #ifndef __STATIC_INLINE + #define __STATIC_INLINE static inline + #endif + #ifndef __STATIC_FORCEINLINE + #define __STATIC_FORCEINLINE __STATIC_INLINE + #endif + #ifndef __NO_RETURN + #define __NO_RETURN __attribute__((noreturn)) + #endif + #ifndef __USED + #define __USED __attribute__((used)) + #endif + #ifndef __WEAK + #define __WEAK __attribute__((weak)) + #endif + #ifndef __PACKED + #define __PACKED __packed__ + #endif + #ifndef __PACKED_STRUCT + #define __PACKED_STRUCT struct __packed__ + #endif + #ifndef __PACKED_UNION + #define __PACKED_UNION union __packed__ + #endif + #ifndef __UNALIGNED_UINT32 /* deprecated */ + struct __packed__ T_UINT32 { uint32_t v; }; + #define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v) + #endif + #ifndef __UNALIGNED_UINT16_WRITE + __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; }; + #define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val)) + #endif + #ifndef __UNALIGNED_UINT16_READ + __PACKED_STRUCT T_UINT16_READ { uint16_t v; }; + #define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v) + #endif + #ifndef __UNALIGNED_UINT32_WRITE + __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; }; + #define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val)) + #endif + #ifndef __UNALIGNED_UINT32_READ + __PACKED_STRUCT T_UINT32_READ { uint32_t v; }; + #define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v) + #endif + #ifndef __ALIGNED + #define __ALIGNED(x) __align(x) + #endif + #ifndef __RESTRICT + #warning No compiler specific solution for __RESTRICT. __RESTRICT is ignored. + #define __RESTRICT + #endif + + +/* + * COSMIC Compiler + */ +#elif defined ( __CSMC__ ) + #include + + #ifndef __ASM + #define __ASM _asm + #endif + #ifndef __INLINE + #define __INLINE inline + #endif + #ifndef __STATIC_INLINE + #define __STATIC_INLINE static inline + #endif + #ifndef __STATIC_FORCEINLINE + #define __STATIC_FORCEINLINE __STATIC_INLINE + #endif + #ifndef __NO_RETURN + // NO RETURN is automatically detected hence no warning here + #define __NO_RETURN + #endif + #ifndef __USED + #warning No compiler specific solution for __USED. __USED is ignored. + #define __USED + #endif + #ifndef __WEAK + #define __WEAK __weak + #endif + #ifndef __PACKED + #define __PACKED @packed + #endif + #ifndef __PACKED_STRUCT + #define __PACKED_STRUCT @packed struct + #endif + #ifndef __PACKED_UNION + #define __PACKED_UNION @packed union + #endif + #ifndef __UNALIGNED_UINT32 /* deprecated */ + @packed struct T_UINT32 { uint32_t v; }; + #define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v) + #endif + #ifndef __UNALIGNED_UINT16_WRITE + __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; }; + #define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val)) + #endif + #ifndef __UNALIGNED_UINT16_READ + __PACKED_STRUCT T_UINT16_READ { uint16_t v; }; + #define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v) + #endif + #ifndef __UNALIGNED_UINT32_WRITE + __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; }; + #define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val)) + #endif + #ifndef __UNALIGNED_UINT32_READ + __PACKED_STRUCT T_UINT32_READ { uint32_t v; }; + #define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v) + #endif + #ifndef __ALIGNED + #warning No compiler specific solution for __ALIGNED. __ALIGNED is ignored. + #define __ALIGNED(x) + #endif + #ifndef __RESTRICT + #warning No compiler specific solution for __RESTRICT. __RESTRICT is ignored. + #define __RESTRICT + #endif + + +#else + #error Unknown compiler. +#endif + + +#endif /* __CMSIS_COMPILER_H */ + diff --git a/src/boards/mcu/samr34/ASF/thirdparty/CMSIS/Include/cmsis_gcc.h b/src/boards/mcu/samr34/ASF/thirdparty/CMSIS/Include/cmsis_gcc.h new file mode 100644 index 000000000..1bd41a495 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/thirdparty/CMSIS/Include/cmsis_gcc.h @@ -0,0 +1,2085 @@ +/**************************************************************************//** + * @file cmsis_gcc.h + * @brief CMSIS compiler GCC header file + * @version V5.0.4 + * @date 09. April 2018 + ******************************************************************************/ +/* + * Copyright (c) 2009-2018 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __CMSIS_GCC_H +#define __CMSIS_GCC_H + +/* ignore some GCC warnings */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsign-conversion" +#pragma GCC diagnostic ignored "-Wconversion" +#pragma GCC diagnostic ignored "-Wunused-parameter" + +/* Fallback for __has_builtin */ +#ifndef __has_builtin + #define __has_builtin(x) (0) +#endif + +/* CMSIS compiler specific defines */ +#ifndef __ASM + #define __ASM __asm +#endif +#ifndef __INLINE + #define __INLINE inline +#endif +#ifndef __STATIC_INLINE + #define __STATIC_INLINE static inline +#endif +#ifndef __STATIC_FORCEINLINE + #define __STATIC_FORCEINLINE __attribute__((always_inline)) static inline +#endif +#ifndef __NO_RETURN + #define __NO_RETURN __attribute__((__noreturn__)) +#endif +#ifndef __USED + #define __USED __attribute__((used)) +#endif +#ifndef __WEAK + #define __WEAK __attribute__((weak)) +#endif +#ifndef __PACKED + #define __PACKED __attribute__((packed, aligned(1))) +#endif +#ifndef __PACKED_STRUCT + #define __PACKED_STRUCT struct __attribute__((packed, aligned(1))) +#endif +#ifndef __PACKED_UNION + #define __PACKED_UNION union __attribute__((packed, aligned(1))) +#endif +#ifndef __UNALIGNED_UINT32 /* deprecated */ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wpacked" + #pragma GCC diagnostic ignored "-Wattributes" + struct __attribute__((packed)) T_UINT32 { uint32_t v; }; + #pragma GCC diagnostic pop + #define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v) +#endif +#ifndef __UNALIGNED_UINT16_WRITE + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wpacked" + #pragma GCC diagnostic ignored "-Wattributes" + __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; }; + #pragma GCC diagnostic pop + #define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val)) +#endif +#ifndef __UNALIGNED_UINT16_READ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wpacked" + #pragma GCC diagnostic ignored "-Wattributes" + __PACKED_STRUCT T_UINT16_READ { uint16_t v; }; + #pragma GCC diagnostic pop + #define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v) +#endif +#ifndef __UNALIGNED_UINT32_WRITE + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wpacked" + #pragma GCC diagnostic ignored "-Wattributes" + __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; }; + #pragma GCC diagnostic pop + #define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val)) +#endif +#ifndef __UNALIGNED_UINT32_READ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wpacked" + #pragma GCC diagnostic ignored "-Wattributes" + __PACKED_STRUCT T_UINT32_READ { uint32_t v; }; + #pragma GCC diagnostic pop + #define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v) +#endif +#ifndef __ALIGNED + #define __ALIGNED(x) __attribute__((aligned(x))) +#endif +#ifndef __RESTRICT + #define __RESTRICT __restrict +#endif + + +/* ########################### Core Function Access ########################### */ +/** \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_RegAccFunctions CMSIS Core Register Access Functions + @{ + */ + +/** + \brief Enable IRQ Interrupts + \details Enables IRQ interrupts by clearing the I-bit in the CPSR. + Can only be executed in Privileged modes. + */ +__STATIC_FORCEINLINE void __enable_irq(void) +{ + __ASM volatile ("cpsie i" : : : "memory"); +} + + +/** + \brief Disable IRQ Interrupts + \details Disables IRQ interrupts by setting the I-bit in the CPSR. + Can only be executed in Privileged modes. + */ +__STATIC_FORCEINLINE void __disable_irq(void) +{ + __ASM volatile ("cpsid i" : : : "memory"); +} + + +/** + \brief Get Control Register + \details Returns the content of the Control Register. + \return Control Register value + */ +__STATIC_FORCEINLINE uint32_t __get_CONTROL(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, control" : "=r" (result) ); + return(result); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Control Register (non-secure) + \details Returns the content of the non-secure Control Register when in secure mode. + \return non-secure Control Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_CONTROL_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, control_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Control Register + \details Writes the given value to the Control Register. + \param [in] control Control Register value to set + */ +__STATIC_FORCEINLINE void __set_CONTROL(uint32_t control) +{ + __ASM volatile ("MSR control, %0" : : "r" (control) : "memory"); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Control Register (non-secure) + \details Writes the given value to the non-secure Control Register when in secure state. + \param [in] control Control Register value to set + */ +__STATIC_FORCEINLINE void __TZ_set_CONTROL_NS(uint32_t control) +{ + __ASM volatile ("MSR control_ns, %0" : : "r" (control) : "memory"); +} +#endif + + +/** + \brief Get IPSR Register + \details Returns the content of the IPSR Register. + \return IPSR Register value + */ +__STATIC_FORCEINLINE uint32_t __get_IPSR(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, ipsr" : "=r" (result) ); + return(result); +} + + +/** + \brief Get APSR Register + \details Returns the content of the APSR Register. + \return APSR Register value + */ +__STATIC_FORCEINLINE uint32_t __get_APSR(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, apsr" : "=r" (result) ); + return(result); +} + + +/** + \brief Get xPSR Register + \details Returns the content of the xPSR Register. + \return xPSR Register value + */ +__STATIC_FORCEINLINE uint32_t __get_xPSR(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, xpsr" : "=r" (result) ); + return(result); +} + + +/** + \brief Get Process Stack Pointer + \details Returns the current value of the Process Stack Pointer (PSP). + \return PSP Register value + */ +__STATIC_FORCEINLINE uint32_t __get_PSP(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, psp" : "=r" (result) ); + return(result); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Process Stack Pointer (non-secure) + \details Returns the current value of the non-secure Process Stack Pointer (PSP) when in secure state. + \return PSP Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_PSP_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, psp_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Process Stack Pointer + \details Assigns the given value to the Process Stack Pointer (PSP). + \param [in] topOfProcStack Process Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __set_PSP(uint32_t topOfProcStack) +{ + __ASM volatile ("MSR psp, %0" : : "r" (topOfProcStack) : ); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Process Stack Pointer (non-secure) + \details Assigns the given value to the non-secure Process Stack Pointer (PSP) when in secure state. + \param [in] topOfProcStack Process Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __TZ_set_PSP_NS(uint32_t topOfProcStack) +{ + __ASM volatile ("MSR psp_ns, %0" : : "r" (topOfProcStack) : ); +} +#endif + + +/** + \brief Get Main Stack Pointer + \details Returns the current value of the Main Stack Pointer (MSP). + \return MSP Register value + */ +__STATIC_FORCEINLINE uint32_t __get_MSP(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, msp" : "=r" (result) ); + return(result); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Main Stack Pointer (non-secure) + \details Returns the current value of the non-secure Main Stack Pointer (MSP) when in secure state. + \return MSP Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_MSP_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, msp_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Main Stack Pointer + \details Assigns the given value to the Main Stack Pointer (MSP). + \param [in] topOfMainStack Main Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __set_MSP(uint32_t topOfMainStack) +{ + __ASM volatile ("MSR msp, %0" : : "r" (topOfMainStack) : ); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Main Stack Pointer (non-secure) + \details Assigns the given value to the non-secure Main Stack Pointer (MSP) when in secure state. + \param [in] topOfMainStack Main Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __TZ_set_MSP_NS(uint32_t topOfMainStack) +{ + __ASM volatile ("MSR msp_ns, %0" : : "r" (topOfMainStack) : ); +} +#endif + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Stack Pointer (non-secure) + \details Returns the current value of the non-secure Stack Pointer (SP) when in secure state. + \return SP Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_SP_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, sp_ns" : "=r" (result) ); + return(result); +} + + +/** + \brief Set Stack Pointer (non-secure) + \details Assigns the given value to the non-secure Stack Pointer (SP) when in secure state. + \param [in] topOfStack Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __TZ_set_SP_NS(uint32_t topOfStack) +{ + __ASM volatile ("MSR sp_ns, %0" : : "r" (topOfStack) : ); +} +#endif + + +/** + \brief Get Priority Mask + \details Returns the current state of the priority mask bit from the Priority Mask Register. + \return Priority Mask value + */ +__STATIC_FORCEINLINE uint32_t __get_PRIMASK(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, primask" : "=r" (result) :: "memory"); + return(result); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Priority Mask (non-secure) + \details Returns the current state of the non-secure priority mask bit from the Priority Mask Register when in secure state. + \return Priority Mask value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_PRIMASK_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, primask_ns" : "=r" (result) :: "memory"); + return(result); +} +#endif + + +/** + \brief Set Priority Mask + \details Assigns the given value to the Priority Mask Register. + \param [in] priMask Priority Mask + */ +__STATIC_FORCEINLINE void __set_PRIMASK(uint32_t priMask) +{ + __ASM volatile ("MSR primask, %0" : : "r" (priMask) : "memory"); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Priority Mask (non-secure) + \details Assigns the given value to the non-secure Priority Mask Register when in secure state. + \param [in] priMask Priority Mask + */ +__STATIC_FORCEINLINE void __TZ_set_PRIMASK_NS(uint32_t priMask) +{ + __ASM volatile ("MSR primask_ns, %0" : : "r" (priMask) : "memory"); +} +#endif + + +#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) +/** + \brief Enable FIQ + \details Enables FIQ interrupts by clearing the F-bit in the CPSR. + Can only be executed in Privileged modes. + */ +__STATIC_FORCEINLINE void __enable_fault_irq(void) +{ + __ASM volatile ("cpsie f" : : : "memory"); +} + + +/** + \brief Disable FIQ + \details Disables FIQ interrupts by setting the F-bit in the CPSR. + Can only be executed in Privileged modes. + */ +__STATIC_FORCEINLINE void __disable_fault_irq(void) +{ + __ASM volatile ("cpsid f" : : : "memory"); +} + + +/** + \brief Get Base Priority + \details Returns the current value of the Base Priority register. + \return Base Priority register value + */ +__STATIC_FORCEINLINE uint32_t __get_BASEPRI(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, basepri" : "=r" (result) ); + return(result); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Base Priority (non-secure) + \details Returns the current value of the non-secure Base Priority register when in secure state. + \return Base Priority register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_BASEPRI_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, basepri_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Base Priority + \details Assigns the given value to the Base Priority register. + \param [in] basePri Base Priority value to set + */ +__STATIC_FORCEINLINE void __set_BASEPRI(uint32_t basePri) +{ + __ASM volatile ("MSR basepri, %0" : : "r" (basePri) : "memory"); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Base Priority (non-secure) + \details Assigns the given value to the non-secure Base Priority register when in secure state. + \param [in] basePri Base Priority value to set + */ +__STATIC_FORCEINLINE void __TZ_set_BASEPRI_NS(uint32_t basePri) +{ + __ASM volatile ("MSR basepri_ns, %0" : : "r" (basePri) : "memory"); +} +#endif + + +/** + \brief Set Base Priority with condition + \details Assigns the given value to the Base Priority register only if BASEPRI masking is disabled, + or the new value increases the BASEPRI priority level. + \param [in] basePri Base Priority value to set + */ +__STATIC_FORCEINLINE void __set_BASEPRI_MAX(uint32_t basePri) +{ + __ASM volatile ("MSR basepri_max, %0" : : "r" (basePri) : "memory"); +} + + +/** + \brief Get Fault Mask + \details Returns the current value of the Fault Mask register. + \return Fault Mask register value + */ +__STATIC_FORCEINLINE uint32_t __get_FAULTMASK(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, faultmask" : "=r" (result) ); + return(result); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Fault Mask (non-secure) + \details Returns the current value of the non-secure Fault Mask register when in secure state. + \return Fault Mask register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_FAULTMASK_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, faultmask_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Fault Mask + \details Assigns the given value to the Fault Mask register. + \param [in] faultMask Fault Mask value to set + */ +__STATIC_FORCEINLINE void __set_FAULTMASK(uint32_t faultMask) +{ + __ASM volatile ("MSR faultmask, %0" : : "r" (faultMask) : "memory"); +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Fault Mask (non-secure) + \details Assigns the given value to the non-secure Fault Mask register when in secure state. + \param [in] faultMask Fault Mask value to set + */ +__STATIC_FORCEINLINE void __TZ_set_FAULTMASK_NS(uint32_t faultMask) +{ + __ASM volatile ("MSR faultmask_ns, %0" : : "r" (faultMask) : "memory"); +} +#endif + +#endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) */ + + +#if ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) + +/** + \brief Get Process Stack Pointer Limit + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence zero is returned always in non-secure + mode. + + \details Returns the current value of the Process Stack Pointer Limit (PSPLIM). + \return PSPLIM Register value + */ +__STATIC_FORCEINLINE uint32_t __get_PSPLIM(void) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + return 0U; +#else + uint32_t result; + __ASM volatile ("MRS %0, psplim" : "=r" (result) ); + return result; +#endif +} + +#if (defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Process Stack Pointer Limit (non-secure) + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence zero is returned always. + + \details Returns the current value of the non-secure Process Stack Pointer Limit (PSPLIM) when in secure state. + \return PSPLIM Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_PSPLIM_NS(void) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + return 0U; +#else + uint32_t result; + __ASM volatile ("MRS %0, psplim_ns" : "=r" (result) ); + return result; +#endif +} +#endif + + +/** + \brief Set Process Stack Pointer Limit + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence the write is silently ignored in non-secure + mode. + + \details Assigns the given value to the Process Stack Pointer Limit (PSPLIM). + \param [in] ProcStackPtrLimit Process Stack Pointer Limit value to set + */ +__STATIC_FORCEINLINE void __set_PSPLIM(uint32_t ProcStackPtrLimit) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + (void)ProcStackPtrLimit; +#else + __ASM volatile ("MSR psplim, %0" : : "r" (ProcStackPtrLimit)); +#endif +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Process Stack Pointer (non-secure) + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence the write is silently ignored. + + \details Assigns the given value to the non-secure Process Stack Pointer Limit (PSPLIM) when in secure state. + \param [in] ProcStackPtrLimit Process Stack Pointer Limit value to set + */ +__STATIC_FORCEINLINE void __TZ_set_PSPLIM_NS(uint32_t ProcStackPtrLimit) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))) + // without main extensions, the non-secure PSPLIM is RAZ/WI + (void)ProcStackPtrLimit; +#else + __ASM volatile ("MSR psplim_ns, %0\n" : : "r" (ProcStackPtrLimit)); +#endif +} +#endif + + +/** + \brief Get Main Stack Pointer Limit + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence zero is returned always in non-secure + mode. + + \details Returns the current value of the Main Stack Pointer Limit (MSPLIM). + \return MSPLIM Register value + */ +__STATIC_FORCEINLINE uint32_t __get_MSPLIM(void) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure MSPLIM is RAZ/WI + return 0U; +#else + uint32_t result; + __ASM volatile ("MRS %0, msplim" : "=r" (result) ); + return result; +#endif +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Get Main Stack Pointer Limit (non-secure) + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence zero is returned always. + + \details Returns the current value of the non-secure Main Stack Pointer Limit(MSPLIM) when in secure state. + \return MSPLIM Register value + */ +__STATIC_FORCEINLINE uint32_t __TZ_get_MSPLIM_NS(void) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))) + // without main extensions, the non-secure MSPLIM is RAZ/WI + return 0U; +#else + uint32_t result; + __ASM volatile ("MRS %0, msplim_ns" : "=r" (result) ); + return result; +#endif +} +#endif + + +/** + \brief Set Main Stack Pointer Limit + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence the write is silently ignored in non-secure + mode. + + \details Assigns the given value to the Main Stack Pointer Limit (MSPLIM). + \param [in] MainStackPtrLimit Main Stack Pointer Limit value to set + */ +__STATIC_FORCEINLINE void __set_MSPLIM(uint32_t MainStackPtrLimit) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ + (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) + // without main extensions, the non-secure MSPLIM is RAZ/WI + (void)MainStackPtrLimit; +#else + __ASM volatile ("MSR msplim, %0" : : "r" (MainStackPtrLimit)); +#endif +} + + +#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) +/** + \brief Set Main Stack Pointer Limit (non-secure) + Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure + Stack Pointer Limit register hence the write is silently ignored. + + \details Assigns the given value to the non-secure Main Stack Pointer Limit (MSPLIM) when in secure state. + \param [in] MainStackPtrLimit Main Stack Pointer value to set + */ +__STATIC_FORCEINLINE void __TZ_set_MSPLIM_NS(uint32_t MainStackPtrLimit) +{ +#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))) + // without main extensions, the non-secure MSPLIM is RAZ/WI + (void)MainStackPtrLimit; +#else + __ASM volatile ("MSR msplim_ns, %0" : : "r" (MainStackPtrLimit)); +#endif +} +#endif + +#endif /* ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) */ + + +/** + \brief Get FPSCR + \details Returns the current value of the Floating Point Status/Control register. + \return Floating Point Status/Control register value + */ +__STATIC_FORCEINLINE uint32_t __get_FPSCR(void) +{ +#if ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ + (defined (__FPU_USED ) && (__FPU_USED == 1U)) ) +#if __has_builtin(__builtin_arm_get_fpscr) +// Re-enable using built-in when GCC has been fixed +// || (__GNUC__ > 7) || (__GNUC__ == 7 && __GNUC_MINOR__ >= 2) + /* see https://gcc.gnu.org/ml/gcc-patches/2017-04/msg00443.html */ + return __builtin_arm_get_fpscr(); +#else + uint32_t result; + + __ASM volatile ("VMRS %0, fpscr" : "=r" (result) ); + return(result); +#endif +#else + return(0U); +#endif +} + + +/** + \brief Set FPSCR + \details Assigns the given value to the Floating Point Status/Control register. + \param [in] fpscr Floating Point Status/Control value to set + */ +__STATIC_FORCEINLINE void __set_FPSCR(uint32_t fpscr) +{ +#if ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ + (defined (__FPU_USED ) && (__FPU_USED == 1U)) ) +#if __has_builtin(__builtin_arm_set_fpscr) +// Re-enable using built-in when GCC has been fixed +// || (__GNUC__ > 7) || (__GNUC__ == 7 && __GNUC_MINOR__ >= 2) + /* see https://gcc.gnu.org/ml/gcc-patches/2017-04/msg00443.html */ + __builtin_arm_set_fpscr(fpscr); +#else + __ASM volatile ("VMSR fpscr, %0" : : "r" (fpscr) : "vfpcc", "memory"); +#endif +#else + (void)fpscr; +#endif +} + + +/*@} end of CMSIS_Core_RegAccFunctions */ + + +/* ########################## Core Instruction Access ######################### */ +/** \defgroup CMSIS_Core_InstructionInterface CMSIS Core Instruction Interface + Access to dedicated instructions + @{ +*/ + +/* Define macros for porting to both thumb1 and thumb2. + * For thumb1, use low register (r0-r7), specified by constraint "l" + * Otherwise, use general registers, specified by constraint "r" */ +#if defined (__thumb__) && !defined (__thumb2__) +#define __CMSIS_GCC_OUT_REG(r) "=l" (r) +#define __CMSIS_GCC_RW_REG(r) "+l" (r) +#define __CMSIS_GCC_USE_REG(r) "l" (r) +#else +#define __CMSIS_GCC_OUT_REG(r) "=r" (r) +#define __CMSIS_GCC_RW_REG(r) "+r" (r) +#define __CMSIS_GCC_USE_REG(r) "r" (r) +#endif + +/** + \brief No Operation + \details No Operation does nothing. This instruction can be used for code alignment purposes. + */ +#define __NOP() __ASM volatile ("nop") + +/** + \brief Wait For Interrupt + \details Wait For Interrupt is a hint instruction that suspends execution until one of a number of events occurs. + */ +#define __WFI() __ASM volatile ("wfi") + + +/** + \brief Wait For Event + \details Wait For Event is a hint instruction that permits the processor to enter + a low-power state until one of a number of events occurs. + */ +#define __WFE() __ASM volatile ("wfe") + + +/** + \brief Send Event + \details Send Event is a hint instruction. It causes an event to be signaled to the CPU. + */ +#define __SEV() __ASM volatile ("sev") + + +/** + \brief Instruction Synchronization Barrier + \details Instruction Synchronization Barrier flushes the pipeline in the processor, + so that all instructions following the ISB are fetched from cache or memory, + after the instruction has been completed. + */ +__STATIC_FORCEINLINE void __ISB(void) +{ + __ASM volatile ("isb 0xF":::"memory"); +} + + +/** + \brief Data Synchronization Barrier + \details Acts as a special kind of Data Memory Barrier. + It completes when all explicit memory accesses before this instruction complete. + */ +__STATIC_FORCEINLINE void __DSB(void) +{ + __ASM volatile ("dsb 0xF":::"memory"); +} + + +/** + \brief Data Memory Barrier + \details Ensures the apparent order of the explicit memory operations before + and after the instruction, without ensuring their completion. + */ +__STATIC_FORCEINLINE void __DMB(void) +{ + __ASM volatile ("dmb 0xF":::"memory"); +} + + +/** + \brief Reverse byte order (32 bit) + \details Reverses the byte order in unsigned integer value. For example, 0x12345678 becomes 0x78563412. + \param [in] value Value to reverse + \return Reversed value + */ +__STATIC_FORCEINLINE uint32_t __REV(uint32_t value) +{ +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) + return __builtin_bswap32(value); +#else + uint32_t result; + + __ASM volatile ("rev %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); + return result; +#endif +} + + +/** + \brief Reverse byte order (16 bit) + \details Reverses the byte order within each halfword of a word. For example, 0x12345678 becomes 0x34127856. + \param [in] value Value to reverse + \return Reversed value + */ +__STATIC_FORCEINLINE uint32_t __REV16(uint32_t value) +{ + uint32_t result; + + __ASM volatile ("rev16 %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); + return result; +} + + +/** + \brief Reverse byte order (16 bit) + \details Reverses the byte order in a 16-bit value and returns the signed 16-bit result. For example, 0x0080 becomes 0x8000. + \param [in] value Value to reverse + \return Reversed value + */ +__STATIC_FORCEINLINE int16_t __REVSH(int16_t value) +{ +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) + return (int16_t)__builtin_bswap16(value); +#else + int16_t result; + + __ASM volatile ("revsh %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); + return result; +#endif +} + + +/** + \brief Rotate Right in unsigned value (32 bit) + \details Rotate Right (immediate) provides the value of the contents of a register rotated by a variable number of bits. + \param [in] op1 Value to rotate + \param [in] op2 Number of Bits to rotate + \return Rotated value + */ +__STATIC_FORCEINLINE uint32_t __ROR(uint32_t op1, uint32_t op2) +{ + op2 %= 32U; + if (op2 == 0U) + { + return op1; + } + return (op1 >> op2) | (op1 << (32U - op2)); +} + + +/** + \brief Breakpoint + \details Causes the processor to enter Debug state. + Debug tools can use this to investigate system state when the instruction at a particular address is reached. + \param [in] value is ignored by the processor. + If required, a debugger can use it to store additional information about the breakpoint. + */ +#define __BKPT(value) __ASM volatile ("bkpt "#value) + + +/** + \brief Reverse bit order of value + \details Reverses the bit order of the given value. + \param [in] value Value to reverse + \return Reversed value + */ +__STATIC_FORCEINLINE uint32_t __RBIT(uint32_t value) +{ + uint32_t result; + +#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) + __ASM volatile ("rbit %0, %1" : "=r" (result) : "r" (value) ); +#else + uint32_t s = (4U /*sizeof(v)*/ * 8U) - 1U; /* extra shift needed at end */ + + result = value; /* r will be reversed bits of v; first get LSB of v */ + for (value >>= 1U; value != 0U; value >>= 1U) + { + result <<= 1U; + result |= value & 1U; + s--; + } + result <<= s; /* shift when v's highest bits are zero */ +#endif + return result; +} + + +/** + \brief Count leading zeros + \details Counts the number of leading zeros of a data value. + \param [in] value Value to count the leading zeros + \return number of leading zeros in value + */ +#define __CLZ (uint8_t)__builtin_clz + + +#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) +/** + \brief LDR Exclusive (8 bit) + \details Executes a exclusive LDR instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +__STATIC_FORCEINLINE uint8_t __LDREXB(volatile uint8_t *addr) +{ + uint32_t result; + +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) + __ASM volatile ("ldrexb %0, %1" : "=r" (result) : "Q" (*addr) ); +#else + /* Prior to GCC 4.8, "Q" will be expanded to [rx, #0] which is not + accepted by assembler. So has to use following less efficient pattern. + */ + __ASM volatile ("ldrexb %0, [%1]" : "=r" (result) : "r" (addr) : "memory" ); +#endif + return ((uint8_t) result); /* Add explicit type cast here */ +} + + +/** + \brief LDR Exclusive (16 bit) + \details Executes a exclusive LDR instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +__STATIC_FORCEINLINE uint16_t __LDREXH(volatile uint16_t *addr) +{ + uint32_t result; + +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) + __ASM volatile ("ldrexh %0, %1" : "=r" (result) : "Q" (*addr) ); +#else + /* Prior to GCC 4.8, "Q" will be expanded to [rx, #0] which is not + accepted by assembler. So has to use following less efficient pattern. + */ + __ASM volatile ("ldrexh %0, [%1]" : "=r" (result) : "r" (addr) : "memory" ); +#endif + return ((uint16_t) result); /* Add explicit type cast here */ +} + + +/** + \brief LDR Exclusive (32 bit) + \details Executes a exclusive LDR instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +__STATIC_FORCEINLINE uint32_t __LDREXW(volatile uint32_t *addr) +{ + uint32_t result; + + __ASM volatile ("ldrex %0, %1" : "=r" (result) : "Q" (*addr) ); + return(result); +} + + +/** + \brief STR Exclusive (8 bit) + \details Executes a exclusive STR instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +__STATIC_FORCEINLINE uint32_t __STREXB(uint8_t value, volatile uint8_t *addr) +{ + uint32_t result; + + __ASM volatile ("strexb %0, %2, %1" : "=&r" (result), "=Q" (*addr) : "r" ((uint32_t)value) ); + return(result); +} + + +/** + \brief STR Exclusive (16 bit) + \details Executes a exclusive STR instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +__STATIC_FORCEINLINE uint32_t __STREXH(uint16_t value, volatile uint16_t *addr) +{ + uint32_t result; + + __ASM volatile ("strexh %0, %2, %1" : "=&r" (result), "=Q" (*addr) : "r" ((uint32_t)value) ); + return(result); +} + + +/** + \brief STR Exclusive (32 bit) + \details Executes a exclusive STR instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +__STATIC_FORCEINLINE uint32_t __STREXW(uint32_t value, volatile uint32_t *addr) +{ + uint32_t result; + + __ASM volatile ("strex %0, %2, %1" : "=&r" (result), "=Q" (*addr) : "r" (value) ); + return(result); +} + + +/** + \brief Remove the exclusive lock + \details Removes the exclusive lock which is created by LDREX. + */ +__STATIC_FORCEINLINE void __CLREX(void) +{ + __ASM volatile ("clrex" ::: "memory"); +} + +#endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) */ + + +#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) +/** + \brief Signed Saturate + \details Saturates a signed value. + \param [in] ARG1 Value to be saturated + \param [in] ARG2 Bit position to saturate to (1..32) + \return Saturated value + */ +#define __SSAT(ARG1,ARG2) \ +__extension__ \ +({ \ + int32_t __RES, __ARG1 = (ARG1); \ + __ASM ("ssat %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) ); \ + __RES; \ + }) + + +/** + \brief Unsigned Saturate + \details Saturates an unsigned value. + \param [in] ARG1 Value to be saturated + \param [in] ARG2 Bit position to saturate to (0..31) + \return Saturated value + */ +#define __USAT(ARG1,ARG2) \ + __extension__ \ +({ \ + uint32_t __RES, __ARG1 = (ARG1); \ + __ASM ("usat %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) ); \ + __RES; \ + }) + + +/** + \brief Rotate Right with Extend (32 bit) + \details Moves each bit of a bitstring right by one bit. + The carry input is shifted in at the left end of the bitstring. + \param [in] value Value to rotate + \return Rotated value + */ +__STATIC_FORCEINLINE uint32_t __RRX(uint32_t value) +{ + uint32_t result; + + __ASM volatile ("rrx %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); + return(result); +} + + +/** + \brief LDRT Unprivileged (8 bit) + \details Executes a Unprivileged LDRT instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +__STATIC_FORCEINLINE uint8_t __LDRBT(volatile uint8_t *ptr) +{ + uint32_t result; + +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) + __ASM volatile ("ldrbt %0, %1" : "=r" (result) : "Q" (*ptr) ); +#else + /* Prior to GCC 4.8, "Q" will be expanded to [rx, #0] which is not + accepted by assembler. So has to use following less efficient pattern. + */ + __ASM volatile ("ldrbt %0, [%1]" : "=r" (result) : "r" (ptr) : "memory" ); +#endif + return ((uint8_t) result); /* Add explicit type cast here */ +} + + +/** + \brief LDRT Unprivileged (16 bit) + \details Executes a Unprivileged LDRT instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +__STATIC_FORCEINLINE uint16_t __LDRHT(volatile uint16_t *ptr) +{ + uint32_t result; + +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) + __ASM volatile ("ldrht %0, %1" : "=r" (result) : "Q" (*ptr) ); +#else + /* Prior to GCC 4.8, "Q" will be expanded to [rx, #0] which is not + accepted by assembler. So has to use following less efficient pattern. + */ + __ASM volatile ("ldrht %0, [%1]" : "=r" (result) : "r" (ptr) : "memory" ); +#endif + return ((uint16_t) result); /* Add explicit type cast here */ +} + + +/** + \brief LDRT Unprivileged (32 bit) + \details Executes a Unprivileged LDRT instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +__STATIC_FORCEINLINE uint32_t __LDRT(volatile uint32_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldrt %0, %1" : "=r" (result) : "Q" (*ptr) ); + return(result); +} + + +/** + \brief STRT Unprivileged (8 bit) + \details Executes a Unprivileged STRT instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STRBT(uint8_t value, volatile uint8_t *ptr) +{ + __ASM volatile ("strbt %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); +} + + +/** + \brief STRT Unprivileged (16 bit) + \details Executes a Unprivileged STRT instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STRHT(uint16_t value, volatile uint16_t *ptr) +{ + __ASM volatile ("strht %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); +} + + +/** + \brief STRT Unprivileged (32 bit) + \details Executes a Unprivileged STRT instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STRT(uint32_t value, volatile uint32_t *ptr) +{ + __ASM volatile ("strt %1, %0" : "=Q" (*ptr) : "r" (value) ); +} + +#else /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) */ + +/** + \brief Signed Saturate + \details Saturates a signed value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (1..32) + \return Saturated value + */ +__STATIC_FORCEINLINE int32_t __SSAT(int32_t val, uint32_t sat) +{ + if ((sat >= 1U) && (sat <= 32U)) + { + const int32_t max = (int32_t)((1U << (sat - 1U)) - 1U); + const int32_t min = -1 - max ; + if (val > max) + { + return max; + } + else if (val < min) + { + return min; + } + } + return val; +} + +/** + \brief Unsigned Saturate + \details Saturates an unsigned value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (0..31) + \return Saturated value + */ +__STATIC_FORCEINLINE uint32_t __USAT(int32_t val, uint32_t sat) +{ + if (sat <= 31U) + { + const uint32_t max = ((1U << sat) - 1U); + if (val > (int32_t)max) + { + return max; + } + else if (val < 0) + { + return 0U; + } + } + return (uint32_t)val; +} + +#endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ + (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ + (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) */ + + +#if ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) +/** + \brief Load-Acquire (8 bit) + \details Executes a LDAB instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +__STATIC_FORCEINLINE uint8_t __LDAB(volatile uint8_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldab %0, %1" : "=r" (result) : "Q" (*ptr) ); + return ((uint8_t) result); +} + + +/** + \brief Load-Acquire (16 bit) + \details Executes a LDAH instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +__STATIC_FORCEINLINE uint16_t __LDAH(volatile uint16_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldah %0, %1" : "=r" (result) : "Q" (*ptr) ); + return ((uint16_t) result); +} + + +/** + \brief Load-Acquire (32 bit) + \details Executes a LDA instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +__STATIC_FORCEINLINE uint32_t __LDA(volatile uint32_t *ptr) +{ + uint32_t result; + + __ASM volatile ("lda %0, %1" : "=r" (result) : "Q" (*ptr) ); + return(result); +} + + +/** + \brief Store-Release (8 bit) + \details Executes a STLB instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STLB(uint8_t value, volatile uint8_t *ptr) +{ + __ASM volatile ("stlb %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); +} + + +/** + \brief Store-Release (16 bit) + \details Executes a STLH instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STLH(uint16_t value, volatile uint16_t *ptr) +{ + __ASM volatile ("stlh %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); +} + + +/** + \brief Store-Release (32 bit) + \details Executes a STL instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__STATIC_FORCEINLINE void __STL(uint32_t value, volatile uint32_t *ptr) +{ + __ASM volatile ("stl %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); +} + + +/** + \brief Load-Acquire Exclusive (8 bit) + \details Executes a LDAB exclusive instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +__STATIC_FORCEINLINE uint8_t __LDAEXB(volatile uint8_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldaexb %0, %1" : "=r" (result) : "Q" (*ptr) ); + return ((uint8_t) result); +} + + +/** + \brief Load-Acquire Exclusive (16 bit) + \details Executes a LDAH exclusive instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +__STATIC_FORCEINLINE uint16_t __LDAEXH(volatile uint16_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldaexh %0, %1" : "=r" (result) : "Q" (*ptr) ); + return ((uint16_t) result); +} + + +/** + \brief Load-Acquire Exclusive (32 bit) + \details Executes a LDA exclusive instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +__STATIC_FORCEINLINE uint32_t __LDAEX(volatile uint32_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldaex %0, %1" : "=r" (result) : "Q" (*ptr) ); + return(result); +} + + +/** + \brief Store-Release Exclusive (8 bit) + \details Executes a STLB exclusive instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +__STATIC_FORCEINLINE uint32_t __STLEXB(uint8_t value, volatile uint8_t *ptr) +{ + uint32_t result; + + __ASM volatile ("stlexb %0, %2, %1" : "=&r" (result), "=Q" (*ptr) : "r" ((uint32_t)value) ); + return(result); +} + + +/** + \brief Store-Release Exclusive (16 bit) + \details Executes a STLH exclusive instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +__STATIC_FORCEINLINE uint32_t __STLEXH(uint16_t value, volatile uint16_t *ptr) +{ + uint32_t result; + + __ASM volatile ("stlexh %0, %2, %1" : "=&r" (result), "=Q" (*ptr) : "r" ((uint32_t)value) ); + return(result); +} + + +/** + \brief Store-Release Exclusive (32 bit) + \details Executes a STL exclusive instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +__STATIC_FORCEINLINE uint32_t __STLEX(uint32_t value, volatile uint32_t *ptr) +{ + uint32_t result; + + __ASM volatile ("stlex %0, %2, %1" : "=&r" (result), "=Q" (*ptr) : "r" ((uint32_t)value) ); + return(result); +} + +#endif /* ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ + (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) */ + +/*@}*/ /* end of group CMSIS_Core_InstructionInterface */ + + +/* ################### Compiler specific Intrinsics ########################### */ +/** \defgroup CMSIS_SIMD_intrinsics CMSIS SIMD Intrinsics + Access to dedicated SIMD instructions + @{ +*/ + +#if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + +__STATIC_FORCEINLINE uint32_t __SADD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("sadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __QADD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("qadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SHADD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("shadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UADD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UQADD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uqadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UHADD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uhadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + + +__STATIC_FORCEINLINE uint32_t __SSUB8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("ssub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __QSUB8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("qsub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SHSUB8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("shsub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __USUB8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("usub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UQSUB8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uqsub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UHSUB8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uhsub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + + +__STATIC_FORCEINLINE uint32_t __SADD16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("sadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __QADD16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("qadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SHADD16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("shadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UADD16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UQADD16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uqadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UHADD16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uhadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SSUB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("ssub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __QSUB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("qsub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SHSUB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("shsub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __USUB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("usub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UQSUB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uqsub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UHSUB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uhsub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SASX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("sasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __QASX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("qasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SHASX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("shasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UASX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UQASX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uqasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UHASX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uhasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SSAX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("ssax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __QSAX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("qsax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SHSAX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("shsax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __USAX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("usax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UQSAX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uqsax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UHSAX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uhsax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __USAD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("usad8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __USADA8(uint32_t op1, uint32_t op2, uint32_t op3) +{ + uint32_t result; + + __ASM volatile ("usada8 %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +#define __SSAT16(ARG1,ARG2) \ +({ \ + int32_t __RES, __ARG1 = (ARG1); \ + __ASM ("ssat16 %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) ); \ + __RES; \ + }) + +#define __USAT16(ARG1,ARG2) \ +({ \ + uint32_t __RES, __ARG1 = (ARG1); \ + __ASM ("usat16 %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) ); \ + __RES; \ + }) + +__STATIC_FORCEINLINE uint32_t __UXTB16(uint32_t op1) +{ + uint32_t result; + + __ASM volatile ("uxtb16 %0, %1" : "=r" (result) : "r" (op1)); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __UXTAB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uxtab16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SXTB16(uint32_t op1) +{ + uint32_t result; + + __ASM volatile ("sxtb16 %0, %1" : "=r" (result) : "r" (op1)); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SXTAB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("sxtab16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SMUAD (uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("smuad %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SMUADX (uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("smuadx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SMLAD (uint32_t op1, uint32_t op2, uint32_t op3) +{ + uint32_t result; + + __ASM volatile ("smlad %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SMLADX (uint32_t op1, uint32_t op2, uint32_t op3) +{ + uint32_t result; + + __ASM volatile ("smladx %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +__STATIC_FORCEINLINE uint64_t __SMLALD (uint32_t op1, uint32_t op2, uint64_t acc) +{ + union llreg_u{ + uint32_t w32[2]; + uint64_t w64; + } llr; + llr.w64 = acc; + +#ifndef __ARMEB__ /* Little endian */ + __ASM volatile ("smlald %0, %1, %2, %3" : "=r" (llr.w32[0]), "=r" (llr.w32[1]): "r" (op1), "r" (op2) , "0" (llr.w32[0]), "1" (llr.w32[1]) ); +#else /* Big endian */ + __ASM volatile ("smlald %0, %1, %2, %3" : "=r" (llr.w32[1]), "=r" (llr.w32[0]): "r" (op1), "r" (op2) , "0" (llr.w32[1]), "1" (llr.w32[0]) ); +#endif + + return(llr.w64); +} + +__STATIC_FORCEINLINE uint64_t __SMLALDX (uint32_t op1, uint32_t op2, uint64_t acc) +{ + union llreg_u{ + uint32_t w32[2]; + uint64_t w64; + } llr; + llr.w64 = acc; + +#ifndef __ARMEB__ /* Little endian */ + __ASM volatile ("smlaldx %0, %1, %2, %3" : "=r" (llr.w32[0]), "=r" (llr.w32[1]): "r" (op1), "r" (op2) , "0" (llr.w32[0]), "1" (llr.w32[1]) ); +#else /* Big endian */ + __ASM volatile ("smlaldx %0, %1, %2, %3" : "=r" (llr.w32[1]), "=r" (llr.w32[0]): "r" (op1), "r" (op2) , "0" (llr.w32[1]), "1" (llr.w32[0]) ); +#endif + + return(llr.w64); +} + +__STATIC_FORCEINLINE uint32_t __SMUSD (uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("smusd %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SMUSDX (uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("smusdx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SMLSD (uint32_t op1, uint32_t op2, uint32_t op3) +{ + uint32_t result; + + __ASM volatile ("smlsd %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +__STATIC_FORCEINLINE uint32_t __SMLSDX (uint32_t op1, uint32_t op2, uint32_t op3) +{ + uint32_t result; + + __ASM volatile ("smlsdx %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +__STATIC_FORCEINLINE uint64_t __SMLSLD (uint32_t op1, uint32_t op2, uint64_t acc) +{ + union llreg_u{ + uint32_t w32[2]; + uint64_t w64; + } llr; + llr.w64 = acc; + +#ifndef __ARMEB__ /* Little endian */ + __ASM volatile ("smlsld %0, %1, %2, %3" : "=r" (llr.w32[0]), "=r" (llr.w32[1]): "r" (op1), "r" (op2) , "0" (llr.w32[0]), "1" (llr.w32[1]) ); +#else /* Big endian */ + __ASM volatile ("smlsld %0, %1, %2, %3" : "=r" (llr.w32[1]), "=r" (llr.w32[0]): "r" (op1), "r" (op2) , "0" (llr.w32[1]), "1" (llr.w32[0]) ); +#endif + + return(llr.w64); +} + +__STATIC_FORCEINLINE uint64_t __SMLSLDX (uint32_t op1, uint32_t op2, uint64_t acc) +{ + union llreg_u{ + uint32_t w32[2]; + uint64_t w64; + } llr; + llr.w64 = acc; + +#ifndef __ARMEB__ /* Little endian */ + __ASM volatile ("smlsldx %0, %1, %2, %3" : "=r" (llr.w32[0]), "=r" (llr.w32[1]): "r" (op1), "r" (op2) , "0" (llr.w32[0]), "1" (llr.w32[1]) ); +#else /* Big endian */ + __ASM volatile ("smlsldx %0, %1, %2, %3" : "=r" (llr.w32[1]), "=r" (llr.w32[0]): "r" (op1), "r" (op2) , "0" (llr.w32[1]), "1" (llr.w32[0]) ); +#endif + + return(llr.w64); +} + +__STATIC_FORCEINLINE uint32_t __SEL (uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("sel %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE int32_t __QADD( int32_t op1, int32_t op2) +{ + int32_t result; + + __ASM volatile ("qadd %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__STATIC_FORCEINLINE int32_t __QSUB( int32_t op1, int32_t op2) +{ + int32_t result; + + __ASM volatile ("qsub %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +#if 0 +#define __PKHBT(ARG1,ARG2,ARG3) \ +({ \ + uint32_t __RES, __ARG1 = (ARG1), __ARG2 = (ARG2); \ + __ASM ("pkhbt %0, %1, %2, lsl %3" : "=r" (__RES) : "r" (__ARG1), "r" (__ARG2), "I" (ARG3) ); \ + __RES; \ + }) + +#define __PKHTB(ARG1,ARG2,ARG3) \ +({ \ + uint32_t __RES, __ARG1 = (ARG1), __ARG2 = (ARG2); \ + if (ARG3 == 0) \ + __ASM ("pkhtb %0, %1, %2" : "=r" (__RES) : "r" (__ARG1), "r" (__ARG2) ); \ + else \ + __ASM ("pkhtb %0, %1, %2, asr %3" : "=r" (__RES) : "r" (__ARG1), "r" (__ARG2), "I" (ARG3) ); \ + __RES; \ + }) +#endif + +#define __PKHBT(ARG1,ARG2,ARG3) ( ((((uint32_t)(ARG1)) ) & 0x0000FFFFUL) | \ + ((((uint32_t)(ARG2)) << (ARG3)) & 0xFFFF0000UL) ) + +#define __PKHTB(ARG1,ARG2,ARG3) ( ((((uint32_t)(ARG1)) ) & 0xFFFF0000UL) | \ + ((((uint32_t)(ARG2)) >> (ARG3)) & 0x0000FFFFUL) ) + +__STATIC_FORCEINLINE int32_t __SMMLA (int32_t op1, int32_t op2, int32_t op3) +{ + int32_t result; + + __ASM volatile ("smmla %0, %1, %2, %3" : "=r" (result): "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +#endif /* (__ARM_FEATURE_DSP == 1) */ +/*@} end of group CMSIS_SIMD_intrinsics */ + + +#pragma GCC diagnostic pop + +#endif /* __CMSIS_GCC_H */ diff --git a/src/boards/mcu/samr34/ASF/thirdparty/CMSIS/Include/cmsis_version.h b/src/boards/mcu/samr34/ASF/thirdparty/CMSIS/Include/cmsis_version.h new file mode 100644 index 000000000..a523d7058 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/thirdparty/CMSIS/Include/cmsis_version.h @@ -0,0 +1,39 @@ +/**************************************************************************//** + * @file cmsis_version.h + * @brief CMSIS Core(M) Version definitions + * @version V5.4.0 + * @date 19. April 2017 + ******************************************************************************/ +/* + * Copyright (c) 2009-2017 ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if defined ( __ICCARM__ ) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined (__clang__) + #pragma clang system_header /* treat file as system include file */ +#endif + +#ifndef __CMSIS_VERSION_H +#define __CMSIS_VERSION_H + +/* CMSIS Version definitions */ +#define __CM_CMSIS_VERSION_MAIN ( 5U) /*!< [31:16] CMSIS Core(M) main version */ +#define __CM_CMSIS_VERSION_SUB ( 1U) /*!< [15:0] CMSIS Core(M) sub version */ +#define __CM_CMSIS_VERSION ((__CM_CMSIS_VERSION_MAIN << 16U) | \ + __CM_CMSIS_VERSION_SUB ) /*!< CMSIS Core(M) version number */ +#endif diff --git a/src/boards/mcu/samr34/ASF/thirdparty/CMSIS/Include/core_cm0plus.h b/src/boards/mcu/samr34/ASF/thirdparty/CMSIS/Include/core_cm0plus.h new file mode 100644 index 000000000..b9377e8c7 --- /dev/null +++ b/src/boards/mcu/samr34/ASF/thirdparty/CMSIS/Include/core_cm0plus.h @@ -0,0 +1,1083 @@ +/**************************************************************************//** + * @file core_cm0plus.h + * @brief CMSIS Cortex-M0+ Core Peripheral Access Layer Header File + * @version V5.0.6 + * @date 28. May 2018 + ******************************************************************************/ +/* + * Copyright (c) 2009-2018 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if defined ( __ICCARM__ ) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined (__clang__) + #pragma clang system_header /* treat file as system include file */ +#endif + +#ifndef __CORE_CM0PLUS_H_GENERIC +#define __CORE_CM0PLUS_H_GENERIC + +#include + +#ifdef __cplusplus + extern "C" { +#endif + +/** + \page CMSIS_MISRA_Exceptions MISRA-C:2004 Compliance Exceptions + CMSIS violates the following MISRA-C:2004 rules: + + \li Required Rule 8.5, object/function definition in header file.
    + Function definitions in header files are used to allow 'inlining'. + + \li Required Rule 18.4, declaration of union type or object of union type: '{...}'.
    + Unions are used for effective representation of core registers. + + \li Advisory Rule 19.7, Function-like macro defined.
    + Function-like macros are used to allow more efficient code. + */ + + +/******************************************************************************* + * CMSIS definitions + ******************************************************************************/ +/** + \ingroup Cortex-M0+ + @{ + */ + +#include "cmsis_version.h" + +/* CMSIS CM0+ definitions */ +#define __CM0PLUS_CMSIS_VERSION_MAIN (__CM_CMSIS_VERSION_MAIN) /*!< \deprecated [31:16] CMSIS HAL main version */ +#define __CM0PLUS_CMSIS_VERSION_SUB (__CM_CMSIS_VERSION_SUB) /*!< \deprecated [15:0] CMSIS HAL sub version */ +#define __CM0PLUS_CMSIS_VERSION ((__CM0PLUS_CMSIS_VERSION_MAIN << 16U) | \ + __CM0PLUS_CMSIS_VERSION_SUB ) /*!< \deprecated CMSIS HAL version number */ + +#define __CORTEX_M (0U) /*!< Cortex-M Core */ + +/** __FPU_USED indicates whether an FPU is used or not. + This core does not support an FPU at all +*/ +#define __FPU_USED 0U + +#if defined ( __CC_ARM ) + #if defined __TARGET_FPU_VFP + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #if defined __ARM_PCS_VFP + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __GNUC__ ) + #if defined (__VFP_FP__) && !defined(__SOFTFP__) + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __ICCARM__ ) + #if defined __ARMVFP__ + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __TI_ARM__ ) + #if defined __TI_VFP_SUPPORT__ + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __TASKING__ ) + #if defined __FPU_VFP__ + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __CSMC__ ) + #if ( __CSMC__ & 0x400U) + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#endif + +#include "cmsis_compiler.h" /* CMSIS compiler specific defines */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_CM0PLUS_H_GENERIC */ + +#ifndef __CMSIS_GENERIC + +#ifndef __CORE_CM0PLUS_H_DEPENDANT +#define __CORE_CM0PLUS_H_DEPENDANT + +#ifdef __cplusplus + extern "C" { +#endif + +/* check device defines and use defaults */ +#if defined __CHECK_DEVICE_DEFINES + #ifndef __CM0PLUS_REV + #define __CM0PLUS_REV 0x0000U + #warning "__CM0PLUS_REV not defined in device header file; using default!" + #endif + + #ifndef __MPU_PRESENT + #define __MPU_PRESENT 0U + #warning "__MPU_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __VTOR_PRESENT + #define __VTOR_PRESENT 0U + #warning "__VTOR_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __NVIC_PRIO_BITS + #define __NVIC_PRIO_BITS 2U + #warning "__NVIC_PRIO_BITS not defined in device header file; using default!" + #endif + + #ifndef __Vendor_SysTickConfig + #define __Vendor_SysTickConfig 0U + #warning "__Vendor_SysTickConfig not defined in device header file; using default!" + #endif +#endif + +/* IO definitions (access restrictions to peripheral registers) */ +/** + \defgroup CMSIS_glob_defs CMSIS Global Defines + + IO Type Qualifiers are used + \li to specify the access to peripheral variables. + \li for automatic generation of peripheral register debug information. +*/ +#ifdef __cplusplus + #define __I volatile /*!< Defines 'read only' permissions */ +#else + #define __I volatile const /*!< Defines 'read only' permissions */ +#endif +#define __O volatile /*!< Defines 'write only' permissions */ +#define __IO volatile /*!< Defines 'read / write' permissions */ + +/* following defines should be used for structure members */ +#define __IM volatile const /*! Defines 'read only' structure member permissions */ +#define __OM volatile /*! Defines 'write only' structure member permissions */ +#define __IOM volatile /*! Defines 'read / write' structure member permissions */ + +/*@} end of group Cortex-M0+ */ + + + +/******************************************************************************* + * Register Abstraction + Core Register contain: + - Core Register + - Core NVIC Register + - Core SCB Register + - Core SysTick Register + - Core MPU Register + ******************************************************************************/ +/** + \defgroup CMSIS_core_register Defines and Type Definitions + \brief Type definitions and defines for Cortex-M processor based devices. +*/ + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_CORE Status and Control Registers + \brief Core Register type definitions. + @{ + */ + +/** + \brief Union type to access the Application Program Status Register (APSR). + */ +typedef union +{ + struct + { + uint32_t _reserved0:28; /*!< bit: 0..27 Reserved */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} APSR_Type; + +/* APSR Register Definitions */ +#define APSR_N_Pos 31U /*!< APSR: N Position */ +#define APSR_N_Msk (1UL << APSR_N_Pos) /*!< APSR: N Mask */ + +#define APSR_Z_Pos 30U /*!< APSR: Z Position */ +#define APSR_Z_Msk (1UL << APSR_Z_Pos) /*!< APSR: Z Mask */ + +#define APSR_C_Pos 29U /*!< APSR: C Position */ +#define APSR_C_Msk (1UL << APSR_C_Pos) /*!< APSR: C Mask */ + +#define APSR_V_Pos 28U /*!< APSR: V Position */ +#define APSR_V_Msk (1UL << APSR_V_Pos) /*!< APSR: V Mask */ + + +/** + \brief Union type to access the Interrupt Program Status Register (IPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ + uint32_t _reserved0:23; /*!< bit: 9..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} IPSR_Type; + +/* IPSR Register Definitions */ +#define IPSR_ISR_Pos 0U /*!< IPSR: ISR Position */ +#define IPSR_ISR_Msk (0x1FFUL /*<< IPSR_ISR_Pos*/) /*!< IPSR: ISR Mask */ + + +/** + \brief Union type to access the Special-Purpose Program Status Registers (xPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ + uint32_t _reserved0:15; /*!< bit: 9..23 Reserved */ + uint32_t T:1; /*!< bit: 24 Thumb bit (read 0) */ + uint32_t _reserved1:3; /*!< bit: 25..27 Reserved */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} xPSR_Type; + +/* xPSR Register Definitions */ +#define xPSR_N_Pos 31U /*!< xPSR: N Position */ +#define xPSR_N_Msk (1UL << xPSR_N_Pos) /*!< xPSR: N Mask */ + +#define xPSR_Z_Pos 30U /*!< xPSR: Z Position */ +#define xPSR_Z_Msk (1UL << xPSR_Z_Pos) /*!< xPSR: Z Mask */ + +#define xPSR_C_Pos 29U /*!< xPSR: C Position */ +#define xPSR_C_Msk (1UL << xPSR_C_Pos) /*!< xPSR: C Mask */ + +#define xPSR_V_Pos 28U /*!< xPSR: V Position */ +#define xPSR_V_Msk (1UL << xPSR_V_Pos) /*!< xPSR: V Mask */ + +#define xPSR_T_Pos 24U /*!< xPSR: T Position */ +#define xPSR_T_Msk (1UL << xPSR_T_Pos) /*!< xPSR: T Mask */ + +#define xPSR_ISR_Pos 0U /*!< xPSR: ISR Position */ +#define xPSR_ISR_Msk (0x1FFUL /*<< xPSR_ISR_Pos*/) /*!< xPSR: ISR Mask */ + + +/** + \brief Union type to access the Control Registers (CONTROL). + */ +typedef union +{ + struct + { + uint32_t nPRIV:1; /*!< bit: 0 Execution privilege in Thread mode */ + uint32_t SPSEL:1; /*!< bit: 1 Stack to be used */ + uint32_t _reserved1:30; /*!< bit: 2..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} CONTROL_Type; + +/* CONTROL Register Definitions */ +#define CONTROL_SPSEL_Pos 1U /*!< CONTROL: SPSEL Position */ +#define CONTROL_SPSEL_Msk (1UL << CONTROL_SPSEL_Pos) /*!< CONTROL: SPSEL Mask */ + +#define CONTROL_nPRIV_Pos 0U /*!< CONTROL: nPRIV Position */ +#define CONTROL_nPRIV_Msk (1UL /*<< CONTROL_nPRIV_Pos*/) /*!< CONTROL: nPRIV Mask */ + +/*@} end of group CMSIS_CORE */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_NVIC Nested Vectored Interrupt Controller (NVIC) + \brief Type definitions for the NVIC Registers + @{ + */ + +/** + \brief Structure type to access the Nested Vectored Interrupt Controller (NVIC). + */ +typedef struct +{ + __IOM uint32_t ISER[1U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */ + uint32_t RESERVED0[31U]; + __IOM uint32_t ICER[1U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */ + uint32_t RSERVED1[31U]; + __IOM uint32_t ISPR[1U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */ + uint32_t RESERVED2[31U]; + __IOM uint32_t ICPR[1U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */ + uint32_t RESERVED3[31U]; + uint32_t RESERVED4[64U]; + __IOM uint32_t IP[8U]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register */ +} NVIC_Type; + +/*@} end of group CMSIS_NVIC */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SCB System Control Block (SCB) + \brief Type definitions for the System Control Block Registers + @{ + */ + +/** + \brief Structure type to access the System Control Block (SCB). + */ +typedef struct +{ + __IM uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPUID Base Register */ + __IOM uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control and State Register */ +#if defined (__VTOR_PRESENT) && (__VTOR_PRESENT == 1U) + __IOM uint32_t VTOR; /*!< Offset: 0x008 (R/W) Vector Table Offset Register */ +#else + uint32_t RESERVED0; +#endif + __IOM uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt and Reset Control Register */ + __IOM uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */ + __IOM uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */ + uint32_t RESERVED1; + __IOM uint32_t SHP[2U]; /*!< Offset: 0x01C (R/W) System Handlers Priority Registers. [0] is RESERVED */ + __IOM uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */ +} SCB_Type; + +/* SCB CPUID Register Definitions */ +#define SCB_CPUID_IMPLEMENTER_Pos 24U /*!< SCB CPUID: IMPLEMENTER Position */ +#define SCB_CPUID_IMPLEMENTER_Msk (0xFFUL << SCB_CPUID_IMPLEMENTER_Pos) /*!< SCB CPUID: IMPLEMENTER Mask */ + +#define SCB_CPUID_VARIANT_Pos 20U /*!< SCB CPUID: VARIANT Position */ +#define SCB_CPUID_VARIANT_Msk (0xFUL << SCB_CPUID_VARIANT_Pos) /*!< SCB CPUID: VARIANT Mask */ + +#define SCB_CPUID_ARCHITECTURE_Pos 16U /*!< SCB CPUID: ARCHITECTURE Position */ +#define SCB_CPUID_ARCHITECTURE_Msk (0xFUL << SCB_CPUID_ARCHITECTURE_Pos) /*!< SCB CPUID: ARCHITECTURE Mask */ + +#define SCB_CPUID_PARTNO_Pos 4U /*!< SCB CPUID: PARTNO Position */ +#define SCB_CPUID_PARTNO_Msk (0xFFFUL << SCB_CPUID_PARTNO_Pos) /*!< SCB CPUID: PARTNO Mask */ + +#define SCB_CPUID_REVISION_Pos 0U /*!< SCB CPUID: REVISION Position */ +#define SCB_CPUID_REVISION_Msk (0xFUL /*<< SCB_CPUID_REVISION_Pos*/) /*!< SCB CPUID: REVISION Mask */ + +/* SCB Interrupt Control State Register Definitions */ +#define SCB_ICSR_NMIPENDSET_Pos 31U /*!< SCB ICSR: NMIPENDSET Position */ +#define SCB_ICSR_NMIPENDSET_Msk (1UL << SCB_ICSR_NMIPENDSET_Pos) /*!< SCB ICSR: NMIPENDSET Mask */ + +#define SCB_ICSR_PENDSVSET_Pos 28U /*!< SCB ICSR: PENDSVSET Position */ +#define SCB_ICSR_PENDSVSET_Msk (1UL << SCB_ICSR_PENDSVSET_Pos) /*!< SCB ICSR: PENDSVSET Mask */ + +#define SCB_ICSR_PENDSVCLR_Pos 27U /*!< SCB ICSR: PENDSVCLR Position */ +#define SCB_ICSR_PENDSVCLR_Msk (1UL << SCB_ICSR_PENDSVCLR_Pos) /*!< SCB ICSR: PENDSVCLR Mask */ + +#define SCB_ICSR_PENDSTSET_Pos 26U /*!< SCB ICSR: PENDSTSET Position */ +#define SCB_ICSR_PENDSTSET_Msk (1UL << SCB_ICSR_PENDSTSET_Pos) /*!< SCB ICSR: PENDSTSET Mask */ + +#define SCB_ICSR_PENDSTCLR_Pos 25U /*!< SCB ICSR: PENDSTCLR Position */ +#define SCB_ICSR_PENDSTCLR_Msk (1UL << SCB_ICSR_PENDSTCLR_Pos) /*!< SCB ICSR: PENDSTCLR Mask */ + +#define SCB_ICSR_ISRPREEMPT_Pos 23U /*!< SCB ICSR: ISRPREEMPT Position */ +#define SCB_ICSR_ISRPREEMPT_Msk (1UL << SCB_ICSR_ISRPREEMPT_Pos) /*!< SCB ICSR: ISRPREEMPT Mask */ + +#define SCB_ICSR_ISRPENDING_Pos 22U /*!< SCB ICSR: ISRPENDING Position */ +#define SCB_ICSR_ISRPENDING_Msk (1UL << SCB_ICSR_ISRPENDING_Pos) /*!< SCB ICSR: ISRPENDING Mask */ + +#define SCB_ICSR_VECTPENDING_Pos 12U /*!< SCB ICSR: VECTPENDING Position */ +#define SCB_ICSR_VECTPENDING_Msk (0x1FFUL << SCB_ICSR_VECTPENDING_Pos) /*!< SCB ICSR: VECTPENDING Mask */ + +#define SCB_ICSR_VECTACTIVE_Pos 0U /*!< SCB ICSR: VECTACTIVE Position */ +#define SCB_ICSR_VECTACTIVE_Msk (0x1FFUL /*<< SCB_ICSR_VECTACTIVE_Pos*/) /*!< SCB ICSR: VECTACTIVE Mask */ + +#if defined (__VTOR_PRESENT) && (__VTOR_PRESENT == 1U) +/* SCB Interrupt Control State Register Definitions */ +#define SCB_VTOR_TBLOFF_Pos 8U /*!< SCB VTOR: TBLOFF Position */ +#define SCB_VTOR_TBLOFF_Msk (0xFFFFFFUL << SCB_VTOR_TBLOFF_Pos) /*!< SCB VTOR: TBLOFF Mask */ +#endif + +/* SCB Application Interrupt and Reset Control Register Definitions */ +#define SCB_AIRCR_VECTKEY_Pos 16U /*!< SCB AIRCR: VECTKEY Position */ +#define SCB_AIRCR_VECTKEY_Msk (0xFFFFUL << SCB_AIRCR_VECTKEY_Pos) /*!< SCB AIRCR: VECTKEY Mask */ + +#define SCB_AIRCR_VECTKEYSTAT_Pos 16U /*!< SCB AIRCR: VECTKEYSTAT Position */ +#define SCB_AIRCR_VECTKEYSTAT_Msk (0xFFFFUL << SCB_AIRCR_VECTKEYSTAT_Pos) /*!< SCB AIRCR: VECTKEYSTAT Mask */ + +#define SCB_AIRCR_ENDIANESS_Pos 15U /*!< SCB AIRCR: ENDIANESS Position */ +#define SCB_AIRCR_ENDIANESS_Msk (1UL << SCB_AIRCR_ENDIANESS_Pos) /*!< SCB AIRCR: ENDIANESS Mask */ + +#define SCB_AIRCR_SYSRESETREQ_Pos 2U /*!< SCB AIRCR: SYSRESETREQ Position */ +#define SCB_AIRCR_SYSRESETREQ_Msk (1UL << SCB_AIRCR_SYSRESETREQ_Pos) /*!< SCB AIRCR: SYSRESETREQ Mask */ + +#define SCB_AIRCR_VECTCLRACTIVE_Pos 1U /*!< SCB AIRCR: VECTCLRACTIVE Position */ +#define SCB_AIRCR_VECTCLRACTIVE_Msk (1UL << SCB_AIRCR_VECTCLRACTIVE_Pos) /*!< SCB AIRCR: VECTCLRACTIVE Mask */ + +/* SCB System Control Register Definitions */ +#define SCB_SCR_SEVONPEND_Pos 4U /*!< SCB SCR: SEVONPEND Position */ +#define SCB_SCR_SEVONPEND_Msk (1UL << SCB_SCR_SEVONPEND_Pos) /*!< SCB SCR: SEVONPEND Mask */ + +#define SCB_SCR_SLEEPDEEP_Pos 2U /*!< SCB SCR: SLEEPDEEP Position */ +#define SCB_SCR_SLEEPDEEP_Msk (1UL << SCB_SCR_SLEEPDEEP_Pos) /*!< SCB SCR: SLEEPDEEP Mask */ + +#define SCB_SCR_SLEEPONEXIT_Pos 1U /*!< SCB SCR: SLEEPONEXIT Position */ +#define SCB_SCR_SLEEPONEXIT_Msk (1UL << SCB_SCR_SLEEPONEXIT_Pos) /*!< SCB SCR: SLEEPONEXIT Mask */ + +/* SCB Configuration Control Register Definitions */ +#define SCB_CCR_STKALIGN_Pos 9U /*!< SCB CCR: STKALIGN Position */ +#define SCB_CCR_STKALIGN_Msk (1UL << SCB_CCR_STKALIGN_Pos) /*!< SCB CCR: STKALIGN Mask */ + +#define SCB_CCR_UNALIGN_TRP_Pos 3U /*!< SCB CCR: UNALIGN_TRP Position */ +#define SCB_CCR_UNALIGN_TRP_Msk (1UL << SCB_CCR_UNALIGN_TRP_Pos) /*!< SCB CCR: UNALIGN_TRP Mask */ + +/* SCB System Handler Control and State Register Definitions */ +#define SCB_SHCSR_SVCALLPENDED_Pos 15U /*!< SCB SHCSR: SVCALLPENDED Position */ +#define SCB_SHCSR_SVCALLPENDED_Msk (1UL << SCB_SHCSR_SVCALLPENDED_Pos) /*!< SCB SHCSR: SVCALLPENDED Mask */ + +/*@} end of group CMSIS_SCB */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SysTick System Tick Timer (SysTick) + \brief Type definitions for the System Timer Registers. + @{ + */ + +/** + \brief Structure type to access the System Timer (SysTick). + */ +typedef struct +{ + __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */ + __IOM uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */ + __IOM uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */ + __IM uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */ +} SysTick_Type; + +/* SysTick Control / Status Register Definitions */ +#define SysTick_CTRL_COUNTFLAG_Pos 16U /*!< SysTick CTRL: COUNTFLAG Position */ +#define SysTick_CTRL_COUNTFLAG_Msk (1UL << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */ + +#define SysTick_CTRL_CLKSOURCE_Pos 2U /*!< SysTick CTRL: CLKSOURCE Position */ +#define SysTick_CTRL_CLKSOURCE_Msk (1UL << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */ + +#define SysTick_CTRL_TICKINT_Pos 1U /*!< SysTick CTRL: TICKINT Position */ +#define SysTick_CTRL_TICKINT_Msk (1UL << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */ + +#define SysTick_CTRL_ENABLE_Pos 0U /*!< SysTick CTRL: ENABLE Position */ +#define SysTick_CTRL_ENABLE_Msk (1UL /*<< SysTick_CTRL_ENABLE_Pos*/) /*!< SysTick CTRL: ENABLE Mask */ + +/* SysTick Reload Register Definitions */ +#define SysTick_LOAD_RELOAD_Pos 0U /*!< SysTick LOAD: RELOAD Position */ +#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL /*<< SysTick_LOAD_RELOAD_Pos*/) /*!< SysTick LOAD: RELOAD Mask */ + +/* SysTick Current Register Definitions */ +#define SysTick_VAL_CURRENT_Pos 0U /*!< SysTick VAL: CURRENT Position */ +#define SysTick_VAL_CURRENT_Msk (0xFFFFFFUL /*<< SysTick_VAL_CURRENT_Pos*/) /*!< SysTick VAL: CURRENT Mask */ + +/* SysTick Calibration Register Definitions */ +#define SysTick_CALIB_NOREF_Pos 31U /*!< SysTick CALIB: NOREF Position */ +#define SysTick_CALIB_NOREF_Msk (1UL << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */ + +#define SysTick_CALIB_SKEW_Pos 30U /*!< SysTick CALIB: SKEW Position */ +#define SysTick_CALIB_SKEW_Msk (1UL << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */ + +#define SysTick_CALIB_TENMS_Pos 0U /*!< SysTick CALIB: TENMS Position */ +#define SysTick_CALIB_TENMS_Msk (0xFFFFFFUL /*<< SysTick_CALIB_TENMS_Pos*/) /*!< SysTick CALIB: TENMS Mask */ + +/*@} end of group CMSIS_SysTick */ + +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_MPU Memory Protection Unit (MPU) + \brief Type definitions for the Memory Protection Unit (MPU) + @{ + */ + +/** + \brief Structure type to access the Memory Protection Unit (MPU). + */ +typedef struct +{ + __IM uint32_t TYPE; /*!< Offset: 0x000 (R/ ) MPU Type Register */ + __IOM uint32_t CTRL; /*!< Offset: 0x004 (R/W) MPU Control Register */ + __IOM uint32_t RNR; /*!< Offset: 0x008 (R/W) MPU Region RNRber Register */ + __IOM uint32_t RBAR; /*!< Offset: 0x00C (R/W) MPU Region Base Address Register */ + __IOM uint32_t RASR; /*!< Offset: 0x010 (R/W) MPU Region Attribute and Size Register */ +} MPU_Type; + +#define MPU_TYPE_RALIASES 1U + +/* MPU Type Register Definitions */ +#define MPU_TYPE_IREGION_Pos 16U /*!< MPU TYPE: IREGION Position */ +#define MPU_TYPE_IREGION_Msk (0xFFUL << MPU_TYPE_IREGION_Pos) /*!< MPU TYPE: IREGION Mask */ + +#define MPU_TYPE_DREGION_Pos 8U /*!< MPU TYPE: DREGION Position */ +#define MPU_TYPE_DREGION_Msk (0xFFUL << MPU_TYPE_DREGION_Pos) /*!< MPU TYPE: DREGION Mask */ + +#define MPU_TYPE_SEPARATE_Pos 0U /*!< MPU TYPE: SEPARATE Position */ +#define MPU_TYPE_SEPARATE_Msk (1UL /*<< MPU_TYPE_SEPARATE_Pos*/) /*!< MPU TYPE: SEPARATE Mask */ + +/* MPU Control Register Definitions */ +#define MPU_CTRL_PRIVDEFENA_Pos 2U /*!< MPU CTRL: PRIVDEFENA Position */ +#define MPU_CTRL_PRIVDEFENA_Msk (1UL << MPU_CTRL_PRIVDEFENA_Pos) /*!< MPU CTRL: PRIVDEFENA Mask */ + +#define MPU_CTRL_HFNMIENA_Pos 1U /*!< MPU CTRL: HFNMIENA Position */ +#define MPU_CTRL_HFNMIENA_Msk (1UL << MPU_CTRL_HFNMIENA_Pos) /*!< MPU CTRL: HFNMIENA Mask */ + +#define MPU_CTRL_ENABLE_Pos 0U /*!< MPU CTRL: ENABLE Position */ +#define MPU_CTRL_ENABLE_Msk (1UL /*<< MPU_CTRL_ENABLE_Pos*/) /*!< MPU CTRL: ENABLE Mask */ + +/* MPU Region Number Register Definitions */ +#define MPU_RNR_REGION_Pos 0U /*!< MPU RNR: REGION Position */ +#define MPU_RNR_REGION_Msk (0xFFUL /*<< MPU_RNR_REGION_Pos*/) /*!< MPU RNR: REGION Mask */ + +/* MPU Region Base Address Register Definitions */ +#define MPU_RBAR_ADDR_Pos 8U /*!< MPU RBAR: ADDR Position */ +#define MPU_RBAR_ADDR_Msk (0xFFFFFFUL << MPU_RBAR_ADDR_Pos) /*!< MPU RBAR: ADDR Mask */ + +#define MPU_RBAR_VALID_Pos 4U /*!< MPU RBAR: VALID Position */ +#define MPU_RBAR_VALID_Msk (1UL << MPU_RBAR_VALID_Pos) /*!< MPU RBAR: VALID Mask */ + +#define MPU_RBAR_REGION_Pos 0U /*!< MPU RBAR: REGION Position */ +#define MPU_RBAR_REGION_Msk (0xFUL /*<< MPU_RBAR_REGION_Pos*/) /*!< MPU RBAR: REGION Mask */ + +/* MPU Region Attribute and Size Register Definitions */ +#define MPU_RASR_ATTRS_Pos 16U /*!< MPU RASR: MPU Region Attribute field Position */ +#define MPU_RASR_ATTRS_Msk (0xFFFFUL << MPU_RASR_ATTRS_Pos) /*!< MPU RASR: MPU Region Attribute field Mask */ + +#define MPU_RASR_XN_Pos 28U /*!< MPU RASR: ATTRS.XN Position */ +#define MPU_RASR_XN_Msk (1UL << MPU_RASR_XN_Pos) /*!< MPU RASR: ATTRS.XN Mask */ + +#define MPU_RASR_AP_Pos 24U /*!< MPU RASR: ATTRS.AP Position */ +#define MPU_RASR_AP_Msk (0x7UL << MPU_RASR_AP_Pos) /*!< MPU RASR: ATTRS.AP Mask */ + +#define MPU_RASR_TEX_Pos 19U /*!< MPU RASR: ATTRS.TEX Position */ +#define MPU_RASR_TEX_Msk (0x7UL << MPU_RASR_TEX_Pos) /*!< MPU RASR: ATTRS.TEX Mask */ + +#define MPU_RASR_S_Pos 18U /*!< MPU RASR: ATTRS.S Position */ +#define MPU_RASR_S_Msk (1UL << MPU_RASR_S_Pos) /*!< MPU RASR: ATTRS.S Mask */ + +#define MPU_RASR_C_Pos 17U /*!< MPU RASR: ATTRS.C Position */ +#define MPU_RASR_C_Msk (1UL << MPU_RASR_C_Pos) /*!< MPU RASR: ATTRS.C Mask */ + +#define MPU_RASR_B_Pos 16U /*!< MPU RASR: ATTRS.B Position */ +#define MPU_RASR_B_Msk (1UL << MPU_RASR_B_Pos) /*!< MPU RASR: ATTRS.B Mask */ + +#define MPU_RASR_SRD_Pos 8U /*!< MPU RASR: Sub-Region Disable Position */ +#define MPU_RASR_SRD_Msk (0xFFUL << MPU_RASR_SRD_Pos) /*!< MPU RASR: Sub-Region Disable Mask */ + +#define MPU_RASR_SIZE_Pos 1U /*!< MPU RASR: Region Size Field Position */ +#define MPU_RASR_SIZE_Msk (0x1FUL << MPU_RASR_SIZE_Pos) /*!< MPU RASR: Region Size Field Mask */ + +#define MPU_RASR_ENABLE_Pos 0U /*!< MPU RASR: Region enable bit Position */ +#define MPU_RASR_ENABLE_Msk (1UL /*<< MPU_RASR_ENABLE_Pos*/) /*!< MPU RASR: Region enable bit Disable Mask */ + +/*@} end of group CMSIS_MPU */ +#endif + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_CoreDebug Core Debug Registers (CoreDebug) + \brief Cortex-M0+ Core Debug Registers (DCB registers, SHCSR, and DFSR) are only accessible over DAP and not via processor. + Therefore they are not covered by the Cortex-M0+ header file. + @{ + */ +/*@} end of group CMSIS_CoreDebug */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_core_bitfield Core register bit field macros + \brief Macros for use with bit field definitions (xxx_Pos, xxx_Msk). + @{ + */ + +/** + \brief Mask and shift a bit field value for use in a register bit range. + \param[in] field Name of the register bit field. + \param[in] value Value of the bit field. This parameter is interpreted as an uint32_t type. + \return Masked and shifted value. +*/ +#define _VAL2FLD(field, value) (((uint32_t)(value) << field ## _Pos) & field ## _Msk) + +/** + \brief Mask and shift a register value to extract a bit filed value. + \param[in] field Name of the register bit field. + \param[in] value Value of register. This parameter is interpreted as an uint32_t type. + \return Masked and shifted bit field value. +*/ +#define _FLD2VAL(field, value) (((uint32_t)(value) & field ## _Msk) >> field ## _Pos) + +/*@} end of group CMSIS_core_bitfield */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_core_base Core Definitions + \brief Definitions for base addresses, unions, and structures. + @{ + */ + +/* Memory mapping of Core Hardware */ +#define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */ +#define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */ +#define NVIC_BASE (SCS_BASE + 0x0100UL) /*!< NVIC Base Address */ +#define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */ + +#define SCB ((SCB_Type *) SCB_BASE ) /*!< SCB configuration struct */ +#define SysTick ((SysTick_Type *) SysTick_BASE ) /*!< SysTick configuration struct */ +#define NVIC ((NVIC_Type *) NVIC_BASE ) /*!< NVIC configuration struct */ + +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) + #define MPU_BASE (SCS_BASE + 0x0D90UL) /*!< Memory Protection Unit */ + #define MPU ((MPU_Type *) MPU_BASE ) /*!< Memory Protection Unit */ +#endif + +/*@} */ + + + +/******************************************************************************* + * Hardware Abstraction Layer + Core Function Interface contains: + - Core NVIC Functions + - Core SysTick Functions + - Core Register Access Functions + ******************************************************************************/ +/** + \defgroup CMSIS_Core_FunctionInterface Functions and Instructions Reference +*/ + + + +/* ########################## NVIC functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_NVICFunctions NVIC Functions + \brief Functions that manage interrupts and exceptions via the NVIC. + @{ + */ + +#ifdef CMSIS_NVIC_VIRTUAL + #ifndef CMSIS_NVIC_VIRTUAL_HEADER_FILE + #define CMSIS_NVIC_VIRTUAL_HEADER_FILE "cmsis_nvic_virtual.h" + #endif + #include CMSIS_NVIC_VIRTUAL_HEADER_FILE +#else + #define NVIC_SetPriorityGrouping __NVIC_SetPriorityGrouping + #define NVIC_GetPriorityGrouping __NVIC_GetPriorityGrouping + #define NVIC_EnableIRQ __NVIC_EnableIRQ + #define NVIC_GetEnableIRQ __NVIC_GetEnableIRQ + #define NVIC_DisableIRQ __NVIC_DisableIRQ + #define NVIC_GetPendingIRQ __NVIC_GetPendingIRQ + #define NVIC_SetPendingIRQ __NVIC_SetPendingIRQ + #define NVIC_ClearPendingIRQ __NVIC_ClearPendingIRQ +/*#define NVIC_GetActive __NVIC_GetActive not available for Cortex-M0+ */ + #define NVIC_SetPriority __NVIC_SetPriority + #define NVIC_GetPriority __NVIC_GetPriority + #define NVIC_SystemReset __NVIC_SystemReset +#endif /* CMSIS_NVIC_VIRTUAL */ + +#ifdef CMSIS_VECTAB_VIRTUAL + #ifndef CMSIS_VECTAB_VIRTUAL_HEADER_FILE + #define CMSIS_VECTAB_VIRTUAL_HEADER_FILE "cmsis_vectab_virtual.h" + #endif + #include CMSIS_VECTAB_VIRTUAL_HEADER_FILE +#else + #define NVIC_SetVector __NVIC_SetVector + #define NVIC_GetVector __NVIC_GetVector +#endif /* (CMSIS_VECTAB_VIRTUAL) */ + +#define NVIC_USER_IRQ_OFFSET 16 + + +/* The following EXC_RETURN values are saved the LR on exception entry */ +#define EXC_RETURN_HANDLER (0xFFFFFFF1UL) /* return to Handler mode, uses MSP after return */ +#define EXC_RETURN_THREAD_MSP (0xFFFFFFF9UL) /* return to Thread mode, uses MSP after return */ +#define EXC_RETURN_THREAD_PSP (0xFFFFFFFDUL) /* return to Thread mode, uses PSP after return */ + + +/* Interrupt Priorities are WORD accessible only under Armv6-M */ +/* The following MACROS handle generation of the register offset and byte masks */ +#define _BIT_SHIFT(IRQn) ( ((((uint32_t)(int32_t)(IRQn)) ) & 0x03UL) * 8UL) +#define _SHP_IDX(IRQn) ( (((((uint32_t)(int32_t)(IRQn)) & 0x0FUL)-8UL) >> 2UL) ) +#define _IP_IDX(IRQn) ( (((uint32_t)(int32_t)(IRQn)) >> 2UL) ) + +#define __NVIC_SetPriorityGrouping(X) (void)(X) +#define __NVIC_GetPriorityGrouping() (0U) + +/** + \brief Enable Interrupt + \details Enables a device specific interrupt in the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ISER[0U] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Get Interrupt Enable status + \details Returns a device specific interrupt enable status from the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt is not enabled. + \return 1 Interrupt is enabled. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t __NVIC_GetEnableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ISER[0U] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Disable Interrupt + \details Disables a device specific interrupt in the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_DisableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ICER[0U] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + __DSB(); + __ISB(); + } +} + + +/** + \brief Get Pending Interrupt + \details Reads the NVIC pending register and returns the pending bit for the specified device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt status is not pending. + \return 1 Interrupt status is pending. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t __NVIC_GetPendingIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ISPR[0U] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Set Pending Interrupt + \details Sets the pending bit of a device specific interrupt in the NVIC pending register. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_SetPendingIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ISPR[0U] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Clear Pending Interrupt + \details Clears the pending bit of a device specific interrupt in the NVIC pending register. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_ClearPendingIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ICPR[0U] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Set Interrupt Priority + \details Sets the priority of a device specific interrupt or a processor exception. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \param [in] priority Priority to set. + \note The priority cannot be set for every processor exception. + */ +__STATIC_INLINE void __NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->IP[_IP_IDX(IRQn)] = ((uint32_t)(NVIC->IP[_IP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn))); + } + else + { + SCB->SHP[_SHP_IDX(IRQn)] = ((uint32_t)(SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn))); + } +} + + +/** + \brief Get Interrupt Priority + \details Reads the priority of a device specific interrupt or a processor exception. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \return Interrupt Priority. + Value is aligned automatically to the implemented priority bits of the microcontroller. + */ +__STATIC_INLINE uint32_t __NVIC_GetPriority(IRQn_Type IRQn) +{ + + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->IP[ _IP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS))); + } + else + { + return((uint32_t)(((SCB->SHP[_SHP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS))); + } +} + + +/** + \brief Encode Priority + \details Encodes the priority for an interrupt with the given priority group, + preemptive priority value, and subpriority value. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. + \param [in] PriorityGroup Used priority group. + \param [in] PreemptPriority Preemptive priority value (starting from 0). + \param [in] SubPriority Subpriority value (starting from 0). + \return Encoded priority. Value can be used in the function \ref NVIC_SetPriority(). + */ +__STATIC_INLINE uint32_t NVIC_EncodePriority (uint32_t PriorityGroup, uint32_t PreemptPriority, uint32_t SubPriority) +{ + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + uint32_t PreemptPriorityBits; + uint32_t SubPriorityBits; + + PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); + SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); + + return ( + ((PreemptPriority & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL)) << SubPriorityBits) | + ((SubPriority & (uint32_t)((1UL << (SubPriorityBits )) - 1UL))) + ); +} + + +/** + \brief Decode Priority + \details Decodes an interrupt priority value with a given priority group to + preemptive priority value and subpriority value. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS) the smallest possible priority group is set. + \param [in] Priority Priority value, which can be retrieved with the function \ref NVIC_GetPriority(). + \param [in] PriorityGroup Used priority group. + \param [out] pPreemptPriority Preemptive priority value (starting from 0). + \param [out] pSubPriority Subpriority value (starting from 0). + */ +__STATIC_INLINE void NVIC_DecodePriority (uint32_t Priority, uint32_t PriorityGroup, uint32_t* const pPreemptPriority, uint32_t* const pSubPriority) +{ + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + uint32_t PreemptPriorityBits; + uint32_t SubPriorityBits; + + PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); + SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); + + *pPreemptPriority = (Priority >> SubPriorityBits) & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL); + *pSubPriority = (Priority ) & (uint32_t)((1UL << (SubPriorityBits )) - 1UL); +} + + +/** + \brief Set Interrupt Vector + \details Sets an interrupt vector in SRAM based interrupt vector table. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + VTOR must been relocated to SRAM before. + If VTOR is not present address 0 must be mapped to SRAM. + \param [in] IRQn Interrupt number + \param [in] vector Address of interrupt handler function + */ +__STATIC_INLINE void __NVIC_SetVector(IRQn_Type IRQn, uint32_t vector) +{ +#if defined (__VTOR_PRESENT) && (__VTOR_PRESENT == 1U) + uint32_t *vectors = (uint32_t *)SCB->VTOR; +#else + uint32_t *vectors = (uint32_t *)0x0U; +#endif + vectors[(int32_t)IRQn + NVIC_USER_IRQ_OFFSET] = vector; +} + + +/** + \brief Get Interrupt Vector + \details Reads an interrupt vector from interrupt vector table. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \return Address of interrupt handler function + */ +__STATIC_INLINE uint32_t __NVIC_GetVector(IRQn_Type IRQn) +{ +#if defined (__VTOR_PRESENT) && (__VTOR_PRESENT == 1U) + uint32_t *vectors = (uint32_t *)SCB->VTOR; +#else + uint32_t *vectors = (uint32_t *)0x0U; +#endif + return vectors[(int32_t)IRQn + NVIC_USER_IRQ_OFFSET]; + +} + + +/** + \brief System Reset + \details Initiates a system reset request to reset the MCU. + */ +__NO_RETURN __STATIC_INLINE void __NVIC_SystemReset(void) +{ + __DSB(); /* Ensure all outstanding memory accesses included + buffered write are completed before reset */ + SCB->AIRCR = ((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + SCB_AIRCR_SYSRESETREQ_Msk); + __DSB(); /* Ensure completion of memory access */ + + for(;;) /* wait until reset */ + { + __NOP(); + } +} + +/*@} end of CMSIS_Core_NVICFunctions */ + +/* ########################## MPU functions #################################### */ + +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) + +#include "mpu_armv7.h" + +#endif + +/* ########################## FPU functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_FpuFunctions FPU Functions + \brief Function that provides FPU type. + @{ + */ + +/** + \brief get FPU type + \details returns the FPU type + \returns + - \b 0: No FPU + - \b 1: Single precision FPU + - \b 2: Double + Single precision FPU + */ +__STATIC_INLINE uint32_t SCB_GetFPUType(void) +{ + return 0U; /* No FPU */ +} + + +/*@} end of CMSIS_Core_FpuFunctions */ + + + +/* ################################## SysTick function ############################################ */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_SysTickFunctions SysTick Functions + \brief Functions that configure the System. + @{ + */ + +#if defined (__Vendor_SysTickConfig) && (__Vendor_SysTickConfig == 0U) + +/** + \brief System Tick Configuration + \details Initializes the System Timer and its interrupt, and starts the System Tick Timer. + Counter is in free running mode to generate periodic interrupts. + \param [in] ticks Number of ticks between two interrupts. + \return 0 Function succeeded. + \return 1 Function failed. + \note When the variable __Vendor_SysTickConfig is set to 1, then the + function SysTick_Config is not included. In this case, the file device.h + must contain a vendor-specific implementation of this function. + */ +__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) +{ + if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) + { + return (1UL); /* Reload value impossible */ + } + + SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */ + NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */ + SysTick->VAL = 0UL; /* Load the SysTick Counter Value */ + SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | + SysTick_CTRL_TICKINT_Msk | + SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */ + return (0UL); /* Function successful */ +} + +#endif + +/*@} end of CMSIS_Core_SysTickFunctions */ + + + + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_CM0PLUS_H_DEPENDANT */ + +#endif /* __CMSIS_GENERIC */ diff --git a/src/boards/mcu/samr34/ASF/thirdparty/CMSIS/Include/mpu_armv7.h b/src/boards/mcu/samr34/ASF/thirdparty/CMSIS/Include/mpu_armv7.h new file mode 100644 index 000000000..7d4b600cc --- /dev/null +++ b/src/boards/mcu/samr34/ASF/thirdparty/CMSIS/Include/mpu_armv7.h @@ -0,0 +1,270 @@ +/****************************************************************************** + * @file mpu_armv7.h + * @brief CMSIS MPU API for Armv7-M MPU + * @version V5.0.4 + * @date 10. January 2018 + ******************************************************************************/ +/* + * Copyright (c) 2017-2018 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if defined ( __ICCARM__ ) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined (__clang__) + #pragma clang system_header /* treat file as system include file */ +#endif + +#ifndef ARM_MPU_ARMV7_H +#define ARM_MPU_ARMV7_H + +#define ARM_MPU_REGION_SIZE_32B ((uint8_t)0x04U) ///!< MPU Region Size 32 Bytes +#define ARM_MPU_REGION_SIZE_64B ((uint8_t)0x05U) ///!< MPU Region Size 64 Bytes +#define ARM_MPU_REGION_SIZE_128B ((uint8_t)0x06U) ///!< MPU Region Size 128 Bytes +#define ARM_MPU_REGION_SIZE_256B ((uint8_t)0x07U) ///!< MPU Region Size 256 Bytes +#define ARM_MPU_REGION_SIZE_512B ((uint8_t)0x08U) ///!< MPU Region Size 512 Bytes +#define ARM_MPU_REGION_SIZE_1KB ((uint8_t)0x09U) ///!< MPU Region Size 1 KByte +#define ARM_MPU_REGION_SIZE_2KB ((uint8_t)0x0AU) ///!< MPU Region Size 2 KBytes +#define ARM_MPU_REGION_SIZE_4KB ((uint8_t)0x0BU) ///!< MPU Region Size 4 KBytes +#define ARM_MPU_REGION_SIZE_8KB ((uint8_t)0x0CU) ///!< MPU Region Size 8 KBytes +#define ARM_MPU_REGION_SIZE_16KB ((uint8_t)0x0DU) ///!< MPU Region Size 16 KBytes +#define ARM_MPU_REGION_SIZE_32KB ((uint8_t)0x0EU) ///!< MPU Region Size 32 KBytes +#define ARM_MPU_REGION_SIZE_64KB ((uint8_t)0x0FU) ///!< MPU Region Size 64 KBytes +#define ARM_MPU_REGION_SIZE_128KB ((uint8_t)0x10U) ///!< MPU Region Size 128 KBytes +#define ARM_MPU_REGION_SIZE_256KB ((uint8_t)0x11U) ///!< MPU Region Size 256 KBytes +#define ARM_MPU_REGION_SIZE_512KB ((uint8_t)0x12U) ///!< MPU Region Size 512 KBytes +#define ARM_MPU_REGION_SIZE_1MB ((uint8_t)0x13U) ///!< MPU Region Size 1 MByte +#define ARM_MPU_REGION_SIZE_2MB ((uint8_t)0x14U) ///!< MPU Region Size 2 MBytes +#define ARM_MPU_REGION_SIZE_4MB ((uint8_t)0x15U) ///!< MPU Region Size 4 MBytes +#define ARM_MPU_REGION_SIZE_8MB ((uint8_t)0x16U) ///!< MPU Region Size 8 MBytes +#define ARM_MPU_REGION_SIZE_16MB ((uint8_t)0x17U) ///!< MPU Region Size 16 MBytes +#define ARM_MPU_REGION_SIZE_32MB ((uint8_t)0x18U) ///!< MPU Region Size 32 MBytes +#define ARM_MPU_REGION_SIZE_64MB ((uint8_t)0x19U) ///!< MPU Region Size 64 MBytes +#define ARM_MPU_REGION_SIZE_128MB ((uint8_t)0x1AU) ///!< MPU Region Size 128 MBytes +#define ARM_MPU_REGION_SIZE_256MB ((uint8_t)0x1BU) ///!< MPU Region Size 256 MBytes +#define ARM_MPU_REGION_SIZE_512MB ((uint8_t)0x1CU) ///!< MPU Region Size 512 MBytes +#define ARM_MPU_REGION_SIZE_1GB ((uint8_t)0x1DU) ///!< MPU Region Size 1 GByte +#define ARM_MPU_REGION_SIZE_2GB ((uint8_t)0x1EU) ///!< MPU Region Size 2 GBytes +#define ARM_MPU_REGION_SIZE_4GB ((uint8_t)0x1FU) ///!< MPU Region Size 4 GBytes + +#define ARM_MPU_AP_NONE 0U ///!< MPU Access Permission no access +#define ARM_MPU_AP_PRIV 1U ///!< MPU Access Permission privileged access only +#define ARM_MPU_AP_URO 2U ///!< MPU Access Permission unprivileged access read-only +#define ARM_MPU_AP_FULL 3U ///!< MPU Access Permission full access +#define ARM_MPU_AP_PRO 5U ///!< MPU Access Permission privileged access read-only +#define ARM_MPU_AP_RO 6U ///!< MPU Access Permission read-only access + +/** MPU Region Base Address Register Value +* +* \param Region The region to be configured, number 0 to 15. +* \param BaseAddress The base address for the region. +*/ +#define ARM_MPU_RBAR(Region, BaseAddress) \ + (((BaseAddress) & MPU_RBAR_ADDR_Msk) | \ + ((Region) & MPU_RBAR_REGION_Msk) | \ + (MPU_RBAR_VALID_Msk)) + +/** +* MPU Memory Access Attributes +* +* \param TypeExtField Type extension field, allows you to configure memory access type, for example strongly ordered, peripheral. +* \param IsShareable Region is shareable between multiple bus masters. +* \param IsCacheable Region is cacheable, i.e. its value may be kept in cache. +* \param IsBufferable Region is bufferable, i.e. using write-back caching. Cacheable but non-bufferable regions use write-through policy. +*/ +#define ARM_MPU_ACCESS_(TypeExtField, IsShareable, IsCacheable, IsBufferable) \ + ((((TypeExtField ) << MPU_RASR_TEX_Pos) & MPU_RASR_TEX_Msk) | \ + (((IsShareable ) << MPU_RASR_S_Pos) & MPU_RASR_S_Msk) | \ + (((IsCacheable ) << MPU_RASR_C_Pos) & MPU_RASR_C_Msk) | \ + (((IsBufferable ) << MPU_RASR_B_Pos) & MPU_RASR_B_Msk)) + +/** +* MPU Region Attribute and Size Register Value +* +* \param DisableExec Instruction access disable bit, 1= disable instruction fetches. +* \param AccessPermission Data access permissions, allows you to configure read/write access for User and Privileged mode. +* \param AccessAttributes Memory access attribution, see \ref ARM_MPU_ACCESS_. +* \param SubRegionDisable Sub-region disable field. +* \param Size Region size of the region to be configured, for example 4K, 8K. +*/ +#define ARM_MPU_RASR_EX(DisableExec, AccessPermission, AccessAttributes, SubRegionDisable, Size) \ + ((((DisableExec ) << MPU_RASR_XN_Pos) & MPU_RASR_XN_Msk) | \ + (((AccessPermission) << MPU_RASR_AP_Pos) & MPU_RASR_AP_Msk) | \ + (((AccessAttributes) ) & (MPU_RASR_TEX_Msk | MPU_RASR_S_Msk | MPU_RASR_C_Msk | MPU_RASR_B_Msk))) + +/** +* MPU Region Attribute and Size Register Value +* +* \param DisableExec Instruction access disable bit, 1= disable instruction fetches. +* \param AccessPermission Data access permissions, allows you to configure read/write access for User and Privileged mode. +* \param TypeExtField Type extension field, allows you to configure memory access type, for example strongly ordered, peripheral. +* \param IsShareable Region is shareable between multiple bus masters. +* \param IsCacheable Region is cacheable, i.e. its value may be kept in cache. +* \param IsBufferable Region is bufferable, i.e. using write-back caching. Cacheable but non-bufferable regions use write-through policy. +* \param SubRegionDisable Sub-region disable field. +* \param Size Region size of the region to be configured, for example 4K, 8K. +*/ +#define ARM_MPU_RASR(DisableExec, AccessPermission, TypeExtField, IsShareable, IsCacheable, IsBufferable, SubRegionDisable, Size) \ + ARM_MPU_RASR_EX(DisableExec, AccessPermission, ARM_MPU_ACCESS_(TypeExtField, IsShareable, IsCacheable, IsBufferable), SubRegionDisable, Size) + +/** +* MPU Memory Access Attribute for strongly ordered memory. +* - TEX: 000b +* - Shareable +* - Non-cacheable +* - Non-bufferable +*/ +#define ARM_MPU_ACCESS_ORDERED ARM_MPU_ACCESS_(0U, 1U, 0U, 0U) + +/** +* MPU Memory Access Attribute for device memory. +* - TEX: 000b (if non-shareable) or 010b (if shareable) +* - Shareable or non-shareable +* - Non-cacheable +* - Bufferable (if shareable) or non-bufferable (if non-shareable) +* +* \param IsShareable Configures the device memory as shareable or non-shareable. +*/ +#define ARM_MPU_ACCESS_DEVICE(IsShareable) ((IsShareable) ? ARM_MPU_ACCESS_(0U, 1U, 0U, 1U) : ARM_MPU_ACCESS_(2U, 0U, 0U, 0U)) + +/** +* MPU Memory Access Attribute for normal memory. +* - TEX: 1BBb (reflecting outer cacheability rules) +* - Shareable or non-shareable +* - Cacheable or non-cacheable (reflecting inner cacheability rules) +* - Bufferable or non-bufferable (reflecting inner cacheability rules) +* +* \param OuterCp Configures the outer cache policy. +* \param InnerCp Configures the inner cache policy. +* \param IsShareable Configures the memory as shareable or non-shareable. +*/ +#define ARM_MPU_ACCESS_NORMAL(OuterCp, InnerCp, IsShareable) ARM_MPU_ACCESS_((4U | (OuterCp)), IsShareable, ((InnerCp) & 2U), ((InnerCp) & 1U)) + +/** +* MPU Memory Access Attribute non-cacheable policy. +*/ +#define ARM_MPU_CACHEP_NOCACHE 0U + +/** +* MPU Memory Access Attribute write-back, write and read allocate policy. +*/ +#define ARM_MPU_CACHEP_WB_WRA 1U + +/** +* MPU Memory Access Attribute write-through, no write allocate policy. +*/ +#define ARM_MPU_CACHEP_WT_NWA 2U + +/** +* MPU Memory Access Attribute write-back, no write allocate policy. +*/ +#define ARM_MPU_CACHEP_WB_NWA 3U + + +/** +* Struct for a single MPU Region +*/ +typedef struct { + uint32_t RBAR; //!< The region base address register value (RBAR) + uint32_t RASR; //!< The region attribute and size register value (RASR) \ref MPU_RASR +} ARM_MPU_Region_t; + +/** Enable the MPU. +* \param MPU_Control Default access permissions for unconfigured regions. +*/ +__STATIC_INLINE void ARM_MPU_Enable(uint32_t MPU_Control) +{ + __DSB(); + __ISB(); + MPU->CTRL = MPU_Control | MPU_CTRL_ENABLE_Msk; +#ifdef SCB_SHCSR_MEMFAULTENA_Msk + SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk; +#endif +} + +/** Disable the MPU. +*/ +__STATIC_INLINE void ARM_MPU_Disable(void) +{ + __DSB(); + __ISB(); +#ifdef SCB_SHCSR_MEMFAULTENA_Msk + SCB->SHCSR &= ~SCB_SHCSR_MEMFAULTENA_Msk; +#endif + MPU->CTRL &= ~MPU_CTRL_ENABLE_Msk; +} + +/** Clear and disable the given MPU region. +* \param rnr Region number to be cleared. +*/ +__STATIC_INLINE void ARM_MPU_ClrRegion(uint32_t rnr) +{ + MPU->RNR = rnr; + MPU->RASR = 0U; +} + +/** Configure an MPU region. +* \param rbar Value for RBAR register. +* \param rsar Value for RSAR register. +*/ +__STATIC_INLINE void ARM_MPU_SetRegion(uint32_t rbar, uint32_t rasr) +{ + MPU->RBAR = rbar; + MPU->RASR = rasr; +} + +/** Configure the given MPU region. +* \param rnr Region number to be configured. +* \param rbar Value for RBAR register. +* \param rsar Value for RSAR register. +*/ +__STATIC_INLINE void ARM_MPU_SetRegionEx(uint32_t rnr, uint32_t rbar, uint32_t rasr) +{ + MPU->RNR = rnr; + MPU->RBAR = rbar; + MPU->RASR = rasr; +} + +/** Memcopy with strictly ordered memory access, e.g. for register targets. +* \param dst Destination data is copied to. +* \param src Source data is copied from. +* \param len Amount of data words to be copied. +*/ +__STATIC_INLINE void orderedCpy(volatile uint32_t* dst, const uint32_t* __RESTRICT src, uint32_t len) +{ + uint32_t i; + for (i = 0U; i < len; ++i) + { + dst[i] = src[i]; + } +} + +/** Load the given number of MPU regions from a table. +* \param table Pointer to the MPU configuration table. +* \param cnt Amount of regions to be configured. +*/ +__STATIC_INLINE void ARM_MPU_Load(ARM_MPU_Region_t const* table, uint32_t cnt) +{ + const uint32_t rowWordSize = sizeof(ARM_MPU_Region_t)/4U; + while (cnt > MPU_TYPE_RALIASES) { + orderedCpy(&(MPU->RBAR), &(table->RBAR), MPU_TYPE_RALIASES*rowWordSize); + table += MPU_TYPE_RALIASES; + cnt -= MPU_TYPE_RALIASES; + } + orderedCpy(&(MPU->RBAR), &(table->RBAR), cnt*rowWordSize); +} + +#endif diff --git a/src/boards/mcu/samr34/ASF/thirdparty/CMSIS/Lib/GCC/libarm_cortexM0l_math.a b/src/boards/mcu/samr34/ASF/thirdparty/CMSIS/Lib/GCC/libarm_cortexM0l_math.a new file mode 100644 index 0000000000000000000000000000000000000000..c91de9d8c2561020cb4be1fa167af98b009f5948 GIT binary patch literal 2768324 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 z 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 z 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