mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
9d596734a1
19752: cpu/atmega_common: checking features instead of CPU models r=benpicco a=hugueslarrive ### Contribution description Splitted from: - #19740 ### Testing procedure Tested on atmega8 with: - #19755 This one probably need to be tested on others cpu. ### Tests on 1284p: #### tests/periph/adc ``` tests/periph/adc$ BOARD=atmega1284p make -j64 clean all | grep '^ ' && BOARD=atmega1284p AVRDUDE_PROGRAMMER='usbasp -F' make flash 2>&1 | grep -- 'of flash' && BOARD=atmega1284p PORT=/dev/ttyACM0 make term text data bss dec hex filename 10712 304 1021 12037 2f05 /home/hugues/github/cpu_atmega_common/RIOT/tests/periph/adc/bin/atmega1284p/tests_adc.elf avrdude: 11016 bytes of flash written avrdude: 11016 bytes of flash verified /home/hugues/github/cpu_atmega_common/RIOT/dist/tools/pyterm/pyterm -p "/dev/ttyACM0" -b "9600" Twisted not available, please install it if you want to use pyterm's JSON capabilities 2023-06-22 18:44:54,846 # Connect to serial port /dev/ttyACM0 Welcome to pyterm! Type '/exit' to exit. 2023-06-22 18:44:55,848 # 2023-06-22 18:44:55,848 # main(): This is RIOT! (Version: 2020.07-devel-15351-gc5f75c-cpu/atmega_common) 2023-06-22 18:44:55,848 # 2023-06-22 18:44:55,849 # RIOT ADC peripheral driver test 2023-06-22 18:44:55,849 # 2023-06-22 18:44:55,850 # This test will sample all available ADC lines once every 100ms with 2023-06-22 18:44:55,850 # a 10-bit resolution and print the sampled results to STDIO 2023-06-22 18:44:55,850 # 2023-06-22 18:44:55,850 # 2023-06-22 18:44:55,851 # Successfully initialized ADC_LINE(0) 2023-06-22 18:44:55,851 # Successfully initialized ADC_LINE(1) 2023-06-22 18:44:55,851 # Successfully initialized ADC_LINE(2) 2023-06-22 18:44:55,852 # Successfully initialized ADC_LINE(3) 2023-06-22 18:44:55,852 # Successfully initialized ADC_LINE(4) 2023-06-22 18:44:55,852 # Successfully initialized ADC_LINE(5) 2023-06-22 18:44:55,853 # Successfully initialized ADC_LINE(6) 2023-06-22 18:44:55,853 # Successfully initialized ADC_LINE(7) 2023-06-22 18:44:55,853 # ADC_LINE(0): 796 2023-06-22 18:44:55,854 # ADC_LINE(1): 599 2023-06-22 18:44:55,854 # ADC_LINE(2): 522 2023-06-22 18:44:55,854 # ADC_LINE(3): 485 2023-06-22 18:44:55,854 # ADC_LINE(4): 466 2023-06-22 18:44:55,854 # ADC_LINE(5): 466 2023-06-22 18:44:55,854 # ADC_LINE(6): 478 2023-06-22 18:44:55,855 # ADC_LINE(7): 501 2023-06-22 18:44:55,855 # Exiting Pyterm make: *** [/home/hugues/github/cpu_atmega_common/RIOT/tests/periph/adc/../../../Makefile.include:879: term] Interrompre ``` #### tests/periph/gpio ``` tests/periph/gpio$ BOARD=atmega1284p make -j64 clean all | grep '^ ' && BOARD=atmega1284p AVRDUDE_PROGRAMMER='usbasp -F' make flash 2>&1 | grep -- 'of flash' && BOARD=atmega1284p PORT=/dev/ttyACM0 make term text data bss dec hex filename 17828 2112 1095 21035 522b /home/hugues/github/cpu_atmega_common/RIOT/tests/periph/gpio/bin/atmega1284p/tests_gpio.elf avrdude: 19940 bytes of flash written avrdude: 19940 bytes of flash verified /home/hugues/github/cpu_atmega_common/RIOT/dist/tools/pyterm/pyterm -p "/dev/ttyACM0" -b "9600" Twisted not available, please install it if you want to use pyterm's JSON capabilities 2023-06-22 18:46:50,726 # Connect to serial port /dev/ttyACM0 Welcome to pyterm! Type '/exit' to exit. 2023-06-22 18:46:51,734 # This is RIOT! (Version: 2020.07-devel-15351-gc5f75c-cpu/atmega_common) 2023-06-22 18:46:51,734 # GPIO peripheral driver test 2023-06-22 18:46:51,734 # 2023-06-22 18:46:51,735 # In this test, pins are specified by integer port and pin numbers. 2023-06-22 18:46:51,735 # So if your platform has a pin PA01, it will be port=0 and pin=1, 2023-06-22 18:46:51,736 # PC14 would be port=2 and pin=14 etc. 2023-06-22 18:46:51,736 # 2023-06-22 18:46:51,736 # NOTE: make sure the values you use exist on your platform! The 2023-06-22 18:46:51,738 # behavior for not existing ports/pins is not defined! init_out 1 5 2023-06-22 18:47:50,380 # init_out 1 5 toggle 1 5 2023-06-22 18:48:09,425 # toggle 1 5 > toggle 1 5 2023-06-22 18:48:12,477 # toggle 1 5 > 2023-06-22 18:48:15,013 # Exiting Pyterm ``` #### tests/periph/i2c ``` tests/periph/i2c$ BOARD=atmega1284p make -j64 clean all | grep '^ ' && BOARD=atmega1284p AVRDUDE_PROGRAMMER='usbasp -F' make flash 2>&1 | grep -- 'of flash' && BOARD=atmega1284p PORT=/dev/ttyACM0 make term text data bss dec hex filename 18634 1288 1215 21137 5291 /home/hugues/github/cpu_atmega_common/RIOT/tests/periph/i2c/bin/atmega1284p/tests_i2c.elf avrdude: 19922 bytes of flash written avrdude: 19922 bytes of flash verified /home/hugues/github/cpu_atmega_common/RIOT/dist/tools/pyterm/pyterm -p "/dev/ttyACM0" -b "9600" Twisted not available, please install it if you want to use pyterm's JSON capabilities 2023-06-22 18:50:37,434 # Connect to serial port /dev/ttyACM0 Welcome to pyterm! Type '/exit' to exit. 2023-06-22 18:50:38,437 # 2023-06-22 18:50:38,438 # main(): This is RIOT! (Version: 2020.07-devel-15351-gc5f75c-cpu/atmega_common) 2023-06-22 18:50:38,438 # Start: Test for the low-level I2C driver > i2c_scan 0 2023-06-22 18:51:37,661 # i2c_scan 0 2023-06-22 18:51:37,687 # Scanning I2C device 0... 2023-06-22 18:51:37,765 # addr not ack'ed = "-", addr ack'ed = "X", addr reserved = "R", error = "E" 2023-06-22 18:51:37,804 # 0 1 2 3 4 5 6 7 8 9 a b c d e f 2023-06-22 18:51:37,842 # 0x00 R R R R R R R R R R R R R R - - 2023-06-22 18:51:37,881 # 0x10 - - - - - - - - - - - - - - - - 2023-06-22 18:51:37,919 # 0x20 - - - - - - - - - - - - - - - - 2023-06-22 18:51:37,958 # 0x30 - - - - - - - - - - - - - - - - 2023-06-22 18:51:37,996 # 0x40 - - - - - - - - - - - - - - - - 2023-06-22 18:51:38,035 # 0x50 - - - - - - - - - - - - - - - - 2023-06-22 18:51:38,073 # 0x60 - - - - - - - - - - - - - - - - 2023-06-22 18:51:38,112 # 0x70 - - - - - - - - R R R R R R R R > 2023-06-22 18:52:54,462 # Exiting Pyterm ``` #### tests/periph/pwm ``` tests/periph/pwm$ BOARD=atmega1284p make -j64 clean all | grep '^ ' && BOARD=atmega1284p AVRDUDE_PROGRAMMER='usbasp -F' make flash 2>&1 | grep -- 'of flash' && BOARD=atmega1284p PORT=/dev/ttyACM0 make term text data bss dec hex filename 15382 896 1093 17371 43db /home/hugues/github/cpu_atmega_common/RIOT/tests/periph/pwm/bin/atmega1284p/tests_pwm.elf avrdude: 16278 bytes of flash written avrdude: 16278 bytes of flash verified /home/hugues/github/cpu_atmega_common/RIOT/dist/tools/pyterm/pyterm -p "/dev/ttyACM0" -b "9600" Twisted not available, please install it if you want to use pyterm's JSON capabilities 2023-06-22 18:54:32,308 # Connect to serial port /dev/ttyACM0 Welcome to pyterm! Type '/exit' to exit. 2023-06-22 18:54:33,310 # 2023-06-22 18:54:33,312 # main(): This is RIOT! (Version: 2020.07-devel-15351-gc5f75c-cpu/atmega_common) 2023-06-22 18:54:33,312 # PWM peripheral driver test 2023-06-22 18:54:33,313 # > osci 2023-06-22 18:54:39,105 # osci 2023-06-22 18:54:39,106 # 2023-06-22 18:54:39,121 # RIOT PWM test 2023-06-22 18:54:39,177 # Connect an LED or scope to PWM pins to see something. 2023-06-22 18:54:39,178 # 2023-06-22 18:54:39,216 # Available PWM device between 0 and 1 2023-06-22 18:54:39,244 # Initialized PWM_0 @ 488Hz. 2023-06-22 18:54:39,273 # Initialized PWM_1 @ 976Hz. 2023-06-22 18:54:39,274 # 2023-06-22 18:54:39,313 # Letting the PWM pins oscillate now... 2023-06-22 18:54:45,655 # Exiting Pyterm ``` #### tests/periph/spi ``` tests/periph/spi$ BOARD=atmega1284p make -j64 clean all | grep '^ ' && BOARD=atmega1284p AVRDUDE_PROGRAMMER='usbasp -F' make flash 2>&1 | grep -- 'of flash' && BOARD=atmega1284p PORT=/dev/ttyACM0 make term text data bss dec hex filename 19240 1402 2317 22959 59af /home/hugues/github/cpu_atmega_common/RIOT/tests/periph/spi/bin/atmega1284p/tests_spi.elf avrdude: 20642 bytes of flash written avrdude: 20642 bytes of flash verified /home/hugues/github/cpu_atmega_common/RIOT/dist/tools/pyterm/pyterm -p "/dev/ttyACM0" -b "9600" Twisted not available, please install it if you want to use pyterm's JSON capabilities 2023-06-22 18:58:12,394 # Connect to serial port /dev/ttyACM0 Welcome to pyterm! Type '/exit' to exit. 2023-06-22 18:58:13,396 # 2023-06-22 18:58:13,398 # main(): This is RIOT! (Version: 2020.07-devel-15351-gc5f75c-cpu/atmega_common) 2023-06-22 18:58:13,398 # Manual SPI peripheral driver test (see README.md) 2023-06-22 18:58:13,399 # There are 1 SPI devices configured for your platform. init 0 0 4 2023-06-22 18:58:32,086 # init 0 0 4 2023-06-22 18:58:32,161 # Trying to initialize SPI_DEV(0): mode: 0, clk: 4, cs_port: 0, cs_pin: 0 2023-06-22 18:58:32,270 # (if below the program crashes with a failed assertion, then it means the configuration is not supported) 2023-06-22 18:58:32,280 # Success. bench 2023-06-22 18:58:41,590 # bench 2023-06-22 18:58:41,644 # ### Running some benchmarks, all values in [us] ### 2023-06-22 18:58:41,682 # ### Test Transfer time user time 2023-06-22 18:58:41,683 # 2023-06-22 18:58:41,755 # 1 - write 1000 times 1 byte: 28456 28640 2023-06-22 18:58:41,827 # 2 - write 1000 times 2 byte: 28184 28352 2023-06-22 18:58:42,454 # 3 - write 1000 times 100 byte: 579528 579704 2023-06-22 18:58:42,563 # 4 - write 1000 times 1 byte to register: 54080 54256 2023-06-22 18:58:42,674 # 5 - write 1000 times 2 byte to register: 56720 56888 2023-06-22 18:58:43,340 # 6 - write 1000 times 100 byte to register: 608152 608320 2023-06-22 18:58:43,412 # 7 - read 1000 times 2 byte: 28304 28480 2023-06-22 18:58:44,025 # 8 - read 1000 times 100 byte: 567408 567576 2023-06-22 18:58:44,138 # 9 - read 1000 times 2 byte from register: 56840 57016 2023-06-22 18:58:44,793 # 10 - read 1000 times 100 byte from register: 596024 596200 2023-06-22 18:58:44,868 # 11 - transfer 1000 times 2 byte: 28336 28512 2023-06-22 18:58:45,510 # 12 - transfer 1000 times 100 byte: 592128 592304 2023-06-22 18:58:45,625 # 13 - transfer 1000 times 2 byte to register: 56960 57136 2023-06-22 18:58:46,306 # 14 - transfer 1000 times 100 byte to register:620744 620920 2023-06-22 18:58:46,373 # 15 - acquire/release 1000 times: 20960 21136 2023-06-22 18:58:46,879 # -- - SUM: 3922824 3925440 2023-06-22 18:58:46,880 # 2023-06-22 18:58:46,907 # ### All runs complete ### > 2023-06-22 18:58:54,706 # Exiting Pyterm ``` I always wonder how fast it really goes: - #16727 - #18374 #### tests/periph/timer ``` tests/periph/timer$ BOARD=atmega1284p make -j64 clean all | grep '^ ' && BOARD=atmega1284p AVRDUDE_PROGRAMMER='usbasp -F' make flash 2>&1 | grep -- 'of flash' && BOARD=atmega1284p PORT=/dev/ttyACM0 make term text data bss dec hex filename 8968 274 1032 10274 2822 /home/hugues/github/cpu_atmega_common/RIOT/tests/periph/timer/bin/atmega1284p/tests_timer.elf avrdude: 9242 bytes of flash written avrdude: 9242 bytes of flash verified /home/hugues/github/cpu_atmega_common/RIOT/dist/tools/pyterm/pyterm -p "/dev/ttyACM0" -b "9600" Twisted not available, please install it if you want to use pyterm's JSON capabilities 2023-06-22 19:00:15,136 # Connect to serial port /dev/ttyACM0 Welcome to pyterm! Type '/exit' to exit. 2023-06-22 19:00:16,138 # 2023-06-22 19:00:16,139 # Help: Press s to start test, r to print it is ready s 2023-06-22 19:00:31,118 # START 2023-06-22 19:00:31,200 # main(): This is RIOT! (Version: 2020.07-devel-15351-gc5f75c-cpu/atmega_common) 2023-06-22 19:00:31,201 # 2023-06-22 19:00:31,230 # Test for peripheral TIMERs 2023-06-22 19:00:31,231 # 2023-06-22 19:00:31,251 # Available timers: 2 2023-06-22 19:00:31,252 # 2023-06-22 19:00:31,270 # Testing TIMER_0: 2023-06-22 19:00:31,306 # TIMER_0: initialization successful 2023-06-22 19:00:31,324 # TIMER_0: stopped 2023-06-22 19:00:31,356 # TIMER_0: set channel 0 to 5000 2023-06-22 19:00:31,390 # TIMER_0: set channel 1 to 10000 2023-06-22 19:00:31,408 # TIMER_0: starting 2023-06-22 19:00:31,482 # TIMER_0: channel 0 fired at SW count 1247 - init: 1247 2023-06-22 19:00:31,547 # TIMER_0: channel 1 fired at SW count 2488 - diff: 1241 2023-06-22 19:00:31,551 # 2023-06-22 19:00:31,568 # Testing TIMER_1: 2023-06-22 19:00:31,605 # TIMER_1: initialization successful 2023-06-22 19:00:31,622 # TIMER_1: stopped 2023-06-22 19:00:31,655 # TIMER_1: set channel 0 to 5000 2023-06-22 19:00:31,688 # TIMER_1: set channel 1 to 10000 2023-06-22 19:00:31,707 # TIMER_1: starting 2023-06-22 19:00:31,780 # TIMER_1: channel 0 fired at SW count 1247 - init: 1247 2023-06-22 19:00:31,846 # TIMER_1: channel 1 fired at SW count 2488 - diff: 1241 2023-06-22 19:00:31,849 # 2023-06-22 19:00:31,864 # TEST SUCCEEDED 2023-06-22 19:00:31,939 # { "threads": [{ "name": "idle", "stack_size": 128, "stack_used": 86 }]} 2023-06-22 19:00:32,015 # { "threads": [{ "name": "main", "stack_size": 640, "stack_used": 120 }]} 2023-06-22 19:00:34,259 # Exiting Pyterm ``` #### tests/periph/uart ``` tests/periph/uart$ BOARD=atmega1284p make -j64 clean all | grep '^ ' && BOARD=atmega1284p AVRDUDE_PROGRAMMER='usbasp -F' make flash 2>&1 | grep -- 'of flash' && BOARD=atmega1284p PORT=/dev/ttyACM0 make term text data bss dec hex filename 15918 1044 2000 18962 4a12 /home/hugues/github/cpu_atmega_common/RIOT/tests/periph/uart/bin/atmega1284p/tests_uart.elf avrdude: 16962 bytes of flash written avrdude: 16962 bytes of flash verified /home/hugues/github/cpu_atmega_common/RIOT/dist/tools/pyterm/pyterm -p "/dev/ttyACM0" -b "9600" Twisted not available, please install it if you want to use pyterm's JSON capabilities 2023-06-22 19:01:25,894 # Connect to serial port /dev/ttyACM0 Welcome to pyterm! Type '/exit' to exit. 2023-06-22 19:01:26,896 # 2023-06-22 19:01:26,898 # main(): This is RIOT! (Version: 2020.07-devel-15351-gc5f75c-cpu/atmega_common) 2023-06-22 19:01:26,898 # 2023-06-22 19:01:26,899 # Manual UART driver test application 2023-06-22 19:01:26,899 # =================================== 2023-06-22 19:01:26,900 # This application is intended for testing additional UART 2023-06-22 19:01:26,900 # interfaces, that might be defined for a board. The 'primary' UART 2023-06-22 19:01:26,901 # interface is tested implicitly, as it is running the shell... 2023-06-22 19:01:26,901 # 2023-06-22 19:01:26,902 # When receiving data on one of the additional UART interfaces, this 2023-06-22 19:01:26,902 # data will be outputted via STDIO. So the easiest way to test an 2023-06-22 19:01:26,903 # UART interface, is to simply connect the RX with the TX pin. Then 2023-06-22 19:01:26,904 # you can send data on that interface and you should see the data 2023-06-22 19:01:26,904 # being printed to STDOUT 2023-06-22 19:01:26,904 # 2023-06-22 19:01:26,904 # NOTE: all strings need to be '\n' terminated! 2023-06-22 19:01:26,904 # 2023-06-22 19:01:26,909 # UARD_DEV(0): test uart_poweron() and uart_poweroff() -> [OK] 2023-06-22 19:01:26,910 # 2023-06-22 19:01:26,921 # UART INFO: 2023-06-22 19:01:26,958 # Available devices: 2 2023-06-22 19:01:27,004 # UART used for STDIO (the shell): UART_DEV(0) 2023-06-22 19:01:27,006 # init 1 9600 2023-06-22 19:01:50,464 # init 1 9600 send 1 ping 2023-06-22 19:04:12,912 # send 1 ping 2023-06-22 19:04:12,934 # UART_DEV(1) TX: ping > 2023-06-22 19:04:12,973 # Success: UART_DEV(1) RX: [ping]\n 2023-06-22 19:04:23,894 # Exiting Pyterm ```` ### Issues/PRs references Depends on PR: - #19751 Co-authored-by: Hugues Larrive <hlarrive@pm.me>
495 lines
12 KiB
C
495 lines
12 KiB
C
/*
|
|
* Copyright (C) 2015 HAW Hamburg
|
|
* 2016 INRIA
|
|
* 2023 Hugues Larrive
|
|
*
|
|
* This file is subject to the terms and conditions of the GNU Lesser
|
|
* General Public License v2.1. See the file LICENSE in the top level
|
|
* directory for more details.
|
|
*/
|
|
|
|
/**
|
|
* @ingroup cpu_atmega_common
|
|
* @ingroup drivers_periph_gpio
|
|
* @{
|
|
*
|
|
* @file
|
|
* @brief Low-level GPIO driver implementation for ATmega family
|
|
*
|
|
* @author René Herthel <rene-herthel@outlook.de>
|
|
* @author Francisco Acosta <francisco.acosta@inria.fr>
|
|
* @author Laurent Navet <laurent.navet@gmail.com>
|
|
* @author Robert Hartung <hartung@ibr.cs.tu-bs.de>
|
|
* @author Torben Petersen <petersen@ibr.cs.tu-bs.de>
|
|
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
|
|
* @author Hugues Larrive <hugues.larrive@pm.me>
|
|
*
|
|
* @}
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <avr/interrupt.h>
|
|
|
|
#include "cpu.h"
|
|
#include "board.h"
|
|
#include "periph/gpio.h"
|
|
#include "periph_conf.h"
|
|
#include "periph_cpu.h"
|
|
#include "atmega_gpio.h"
|
|
|
|
#define ENABLE_DEBUG 0
|
|
#include "debug.h"
|
|
|
|
#ifdef MODULE_PERIPH_GPIO_IRQ
|
|
|
|
static gpio_isr_ctx_t config[GPIO_EXT_INT_NUMOF];
|
|
|
|
/* Detects amount of possible PCINTs */
|
|
#if defined(MODULE_ATMEGA_PCINT0) || defined(MODULE_ATMEGA_PCINT1) || \
|
|
defined(MODULE_ATMEGA_PCINT2) || defined(MODULE_ATMEGA_PCINT3)
|
|
#include "atmega_pcint.h"
|
|
|
|
#define ENABLE_PCINT
|
|
|
|
/* Check which pcints should be enabled */
|
|
#if defined(MODULE_ATMEGA_PCINT0) && !defined(ATMEGA_PCINT_MAP_PCINT0)
|
|
# error "Either mapping for pin change interrupt bank 0 is missing or not supported by the MCU"
|
|
#endif
|
|
|
|
#if defined(MODULE_ATMEGA_PCINT1) && !defined(ATMEGA_PCINT_MAP_PCINT1)
|
|
# error "Either mapping for pin change interrupt bank 1 is missing or not supported by the MCU"
|
|
#endif
|
|
|
|
#if defined(MODULE_ATMEGA_PCINT2) && !defined(ATMEGA_PCINT_MAP_PCINT2)
|
|
# error "Either mapping for pin change interrupt bank 2 is missing or not supported by the MCU"
|
|
#endif
|
|
|
|
#if defined(MODULE_ATMEGA_PCINT3) && !defined(ATMEGA_PCINT_MAP_PCINT3)
|
|
# error "Either mapping for pin change interrupt bank 3 is missing or not supported by the MCU"
|
|
#endif
|
|
|
|
/**
|
|
* @brief Use anonymous enum as for addressing the @ref pcint_state
|
|
*/
|
|
enum {
|
|
#ifdef MODULE_ATMEGA_PCINT0
|
|
PCINT0_IDX, /**< Index of PCINT0, if used */
|
|
#endif /* MODULE_ATMEGA_PCINT0 */
|
|
#ifdef MODULE_ATMEGA_PCINT1
|
|
PCINT1_IDX, /**< Index of PCINT1, if used */
|
|
#endif /* MODULE_ATMEGA_PCINT1 */
|
|
#ifdef MODULE_ATMEGA_PCINT2
|
|
PCINT2_IDX, /**< Index of PCINT2, if used */
|
|
#endif /* MODULE_ATMEGA_PCINT2 */
|
|
#ifdef MODULE_ATMEGA_PCINT3
|
|
PCINT3_IDX, /**< Index of PCINT3, if used */
|
|
#endif /* MODULE_ATMEGA_PCINT3 */
|
|
PCINT_NUM_BANKS /**< Number of PCINT banks used */
|
|
};
|
|
|
|
/**
|
|
* @brief stores the last pcint state of each port
|
|
*/
|
|
static uint8_t pcint_state[PCINT_NUM_BANKS];
|
|
|
|
/**
|
|
* @brief stores all cb and args for all defined pcint.
|
|
*/
|
|
typedef struct {
|
|
gpio_flank_t flank; /**< type of interrupt the flank should be triggered on */
|
|
gpio_cb_t cb; /**< interrupt callback */
|
|
void *arg; /**< optional argument */
|
|
} gpio_isr_ctx_pcint_t;
|
|
|
|
/**
|
|
* @brief
|
|
*/
|
|
static const gpio_t pcint_mapping[] = {
|
|
#ifdef MODULE_ATMEGA_PCINT0
|
|
ATMEGA_PCINT_MAP_PCINT0,
|
|
#endif /* PCINT0_IDX */
|
|
#ifdef MODULE_ATMEGA_PCINT1
|
|
ATMEGA_PCINT_MAP_PCINT1,
|
|
#endif /* PCINT1_IDX */
|
|
#ifdef MODULE_ATMEGA_PCINT2
|
|
ATMEGA_PCINT_MAP_PCINT2,
|
|
#endif /* PCINT2_IDX */
|
|
#ifdef MODULE_ATMEGA_PCINT3
|
|
ATMEGA_PCINT_MAP_PCINT3,
|
|
#endif /* PCINT3_IDX */
|
|
};
|
|
/**
|
|
* @brief
|
|
*/
|
|
static gpio_isr_ctx_pcint_t pcint_config[8 * PCINT_NUM_BANKS];
|
|
#endif /* MODULE_ATMEGA_PCINTn */
|
|
|
|
#endif /* MODULE_PERIPH_GPIO_IRQ */
|
|
|
|
int gpio_init(gpio_t pin, gpio_mode_t mode)
|
|
{
|
|
uint8_t pin_mask = (1 << atmega_pin_num(pin));
|
|
|
|
switch (mode) {
|
|
case GPIO_OUT:
|
|
_SFR_MEM8(atmega_ddr_addr(pin)) |= pin_mask;
|
|
break;
|
|
case GPIO_IN:
|
|
_SFR_MEM8(atmega_ddr_addr(pin)) &= ~pin_mask;
|
|
_SFR_MEM8(atmega_port_addr(pin)) &= ~pin_mask;
|
|
break;
|
|
case GPIO_IN_PU:
|
|
_SFR_MEM8(atmega_ddr_addr(pin)) &= ~pin_mask;
|
|
_SFR_MEM8(atmega_port_addr(pin)) |= pin_mask;
|
|
break;
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int gpio_read(gpio_t pin)
|
|
{
|
|
return (_SFR_MEM8(atmega_pin_addr(pin)) & (1 << atmega_pin_num(pin)));
|
|
}
|
|
|
|
void gpio_set(gpio_t pin)
|
|
{
|
|
_SFR_MEM8(atmega_port_addr(pin)) |= (1 << atmega_pin_num(pin));
|
|
}
|
|
|
|
void gpio_clear(gpio_t pin)
|
|
{
|
|
_SFR_MEM8(atmega_port_addr(pin)) &= ~(1 << atmega_pin_num(pin));
|
|
}
|
|
|
|
void gpio_toggle(gpio_t pin)
|
|
{
|
|
if (gpio_read(pin)) {
|
|
gpio_clear(pin);
|
|
}
|
|
else {
|
|
gpio_set(pin);
|
|
}
|
|
}
|
|
|
|
void gpio_write(gpio_t pin, int value)
|
|
{
|
|
if (value) {
|
|
gpio_set(pin);
|
|
}
|
|
else {
|
|
gpio_clear(pin);
|
|
}
|
|
}
|
|
|
|
#ifdef MODULE_PERIPH_GPIO_IRQ
|
|
static inline int8_t _int_num(gpio_t pin)
|
|
{
|
|
uint8_t num;
|
|
const gpio_t ext_ints[GPIO_EXT_INT_NUMOF] = CPU_ATMEGA_EXT_INTS;
|
|
|
|
/* find pin in ext_ints array to get the interrupt number */
|
|
for (num = 0; num < GPIO_EXT_INT_NUMOF; num++) {
|
|
if (pin == ext_ints[num]) {
|
|
return num;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
#ifdef ENABLE_PCINT
|
|
static inline int pcint_init_int(gpio_t pin, gpio_mode_t mode,
|
|
gpio_flank_t flank,
|
|
gpio_cb_t cb, void *arg)
|
|
{
|
|
int8_t offset = -1;
|
|
uint8_t pin_num = atmega_pin_num(pin);
|
|
|
|
for (unsigned i = 0; i < ARRAY_SIZE(pcint_mapping); i++) {
|
|
if (pin != GPIO_UNDEF && pin == pcint_mapping[i]) {
|
|
offset = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* if pcint was not found: return -1 */
|
|
if (offset < 0) {
|
|
return offset;
|
|
}
|
|
|
|
uint8_t bank = offset / 8;
|
|
uint8_t bank_idx = offset % 8;
|
|
DEBUG("PCINT enabled for bank %u offset %u\n",
|
|
(unsigned)bank, (unsigned)offset);
|
|
|
|
/* save configuration for pin change interrupt */
|
|
pcint_config[offset].flank = flank;
|
|
pcint_config[offset].arg = arg;
|
|
pcint_config[offset].cb = cb;
|
|
|
|
/* init gpio */
|
|
gpio_init(pin, mode);
|
|
/* configure pcint */
|
|
cli();
|
|
switch (bank) {
|
|
#ifdef MODULE_ATMEGA_PCINT0
|
|
case PCINT0_IDX:
|
|
PCMSK0 |= (1 << bank_idx);
|
|
PCICR |= (1 << PCIE0);
|
|
break;
|
|
#endif /* MODULE_ATMEGA_PCINT0 */
|
|
#ifdef MODULE_ATMEGA_PCINT1
|
|
case PCINT1_IDX:
|
|
PCMSK1 |= (1 << bank_idx);
|
|
PCICR |= (1 << PCIE1);
|
|
break;
|
|
#endif /* MODULE_ATMEGA_PCINT1 */
|
|
#ifdef MODULE_ATMEGA_PCINT2
|
|
case PCINT2_IDX:
|
|
PCMSK2 |= (1 << bank_idx);
|
|
PCICR |= (1 << PCIE2);
|
|
break;
|
|
#endif /* MODULE_ATMEGA_PCINT2 */
|
|
#ifdef MODULE_ATMEGA_PCINT3
|
|
case PCINT3_IDX:
|
|
PCMSK3 |= (1 << bank_idx);
|
|
PCICR |= (1 << PCIE3);
|
|
break;
|
|
#endif /* MODULE_ATMEGA_PCINT3 */
|
|
default:
|
|
return -1;
|
|
break;
|
|
}
|
|
/* As ports are mixed in a bank (e.g. PCINT0), we can only save a single bit here! */
|
|
uint8_t port_value = (_SFR_MEM8(atmega_pin_addr( pin )));
|
|
uint8_t pin_mask = (1 << pin_num);
|
|
uint8_t pin_value = ((port_value & pin_mask) != 0);
|
|
if (pin_value) {
|
|
pcint_state[bank] |= pin_mask;
|
|
}
|
|
else {
|
|
pcint_state[bank] &= ~pin_mask;
|
|
}
|
|
sei();
|
|
return 0;
|
|
}
|
|
#endif /* ENABLE_PCINT */
|
|
|
|
int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank,
|
|
gpio_cb_t cb, void *arg)
|
|
{
|
|
int8_t int_num = _int_num(pin);
|
|
|
|
/* mode not supported */
|
|
if ((mode != GPIO_IN) && (mode != GPIO_IN_PU)) {
|
|
return -1;
|
|
}
|
|
|
|
/* not a valid interrupt pin. Set as pcint instead if pcints are enabled */
|
|
if (int_num < 0) {
|
|
#ifdef ENABLE_PCINT
|
|
/* If pin change interrupts are enabled, enable mask and interrupt */
|
|
return pcint_init_int(pin, mode, flank, cb, arg);
|
|
#else
|
|
return -1;
|
|
#endif /* ENABLE_PCINT */
|
|
}
|
|
|
|
/* flank not supported */
|
|
if (flank > GPIO_RISING) {
|
|
return -1;
|
|
}
|
|
|
|
gpio_init(pin, mode);
|
|
|
|
/* clear global interrupt flag */
|
|
cli();
|
|
|
|
/* enable interrupt number int_num */
|
|
#if defined(EIFR) && defined(EIMSK)
|
|
EIFR |= (1 << int_num);
|
|
EIMSK |= (1 << int_num);
|
|
#elif defined(GIFR) && defined(GICR)
|
|
GIFR |= (1 << (INTF0 + int_num));
|
|
GICR |= (1 << (INT0 + int_num));
|
|
#endif
|
|
|
|
/* apply flank to interrupt number int_num */
|
|
#if defined(EICRB)
|
|
if (int_num >= 4) {
|
|
EICRB &= ~(0x3 << ((int_num % 4) * 2));
|
|
EICRB |= (flank << ((int_num % 4) * 2));
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
#if defined(EICRA)
|
|
EICRA &= ~(0x3 << (int_num * 2));
|
|
EICRA |= (flank << (int_num * 2));
|
|
#elif defined(MCUCR)
|
|
MCUCR &= ~(0x3 << (int_num * 2));
|
|
MCUCR |= (flank << (int_num * 2));
|
|
#endif
|
|
}
|
|
|
|
/* set callback */
|
|
config[int_num].cb = cb;
|
|
config[int_num].arg = arg;
|
|
|
|
/* set global interrupt flag */
|
|
sei();
|
|
|
|
return 0;
|
|
}
|
|
|
|
void gpio_irq_enable(gpio_t pin)
|
|
{
|
|
#if defined(EIFR) && defined(EIMSK)
|
|
EIFR |= (1 << _int_num(pin));
|
|
EIMSK |= (1 << _int_num(pin));
|
|
#elif defined(GIFR) && defined(GICR)
|
|
GIFR |= (1 << (INTF0 + _int_num(pin)));
|
|
GICR |= (1 << (INT0 + _int_num(pin)));
|
|
#endif
|
|
}
|
|
|
|
void gpio_irq_disable(gpio_t pin)
|
|
{
|
|
#if defined(EIMSK)
|
|
EIMSK &= ~(1 << _int_num(pin));
|
|
#elif defined(GICR)
|
|
GICR &= ~(1 << (INT0 + _int_num(pin)));
|
|
#endif
|
|
}
|
|
|
|
static inline void irq_handler(uint8_t int_num)
|
|
{
|
|
avr8_enter_isr();
|
|
config[int_num].cb(config[int_num].arg);
|
|
avr8_exit_isr();
|
|
}
|
|
|
|
#ifdef ENABLE_PCINT
|
|
/* inline function that is used by the PCINT ISR */
|
|
static inline void pcint_handler(uint8_t bank, uint8_t enabled_pcints)
|
|
{
|
|
avr8_enter_isr();
|
|
/* Find right item */
|
|
uint8_t idx = 0;
|
|
|
|
while (enabled_pcints > 0) {
|
|
/* check if this pin is enabled & has changed */
|
|
if (enabled_pcints & 0x1) {
|
|
/* get pin from mapping (assumes 8 entries per bank!) */
|
|
gpio_t pin = pcint_mapping[bank * 8 + idx];
|
|
/* re-construct mask from pin */
|
|
uint8_t pin_mask = (1 << (atmega_pin_num(pin)));
|
|
uint8_t idx_mask = (1 << idx);
|
|
uint8_t port_value = (_SFR_MEM8(atmega_pin_addr( pin )));
|
|
uint8_t pin_value = ((port_value & pin_mask) != 0);
|
|
uint8_t old_state = ((pcint_state[bank] & idx_mask) != 0);
|
|
gpio_isr_ctx_pcint_t *conf = &pcint_config[bank * 8 + idx];
|
|
if (old_state != pin_value) {
|
|
pcint_state[bank] ^= idx_mask;
|
|
if ((conf->flank == GPIO_BOTH ||
|
|
(pin_value && conf->flank == GPIO_RISING) ||
|
|
(!pin_value && conf->flank == GPIO_FALLING))) {
|
|
/* execute callback routine */
|
|
conf->cb(conf->arg);
|
|
}
|
|
}
|
|
}
|
|
enabled_pcints = enabled_pcints >> 1;
|
|
idx++;
|
|
}
|
|
|
|
avr8_exit_isr();
|
|
}
|
|
#ifdef MODULE_ATMEGA_PCINT0
|
|
ISR(PCINT0_vect, ISR_BLOCK)
|
|
{
|
|
pcint_handler(PCINT0_IDX, PCMSK0);
|
|
}
|
|
#endif /* MODULE_ATMEGA_PCINT0 */
|
|
|
|
#ifdef MODULE_ATMEGA_PCINT1
|
|
ISR(PCINT1_vect, ISR_BLOCK)
|
|
{
|
|
pcint_handler(PCINT1_IDX, PCMSK1);
|
|
}
|
|
#endif /* MODULE_ATMEGA_PCINT1 */
|
|
|
|
#ifdef MODULE_ATMEGA_PCINT2
|
|
ISR(PCINT2_vect, ISR_BLOCK)
|
|
{
|
|
pcint_handler(PCINT2_IDX, PCMSK2);
|
|
}
|
|
#endif /* MODULE_ATMEGA_PCINT2 */
|
|
|
|
#ifdef MODULE_ATMEGA_PCINT3
|
|
ISR(PCINT3_vect, ISR_BLOCK)
|
|
{
|
|
pcint_handler(PCINT3_IDX, PCMSK3);
|
|
}
|
|
#endif /* MODULE_ATMEGA_PCINT3 */
|
|
|
|
#endif /* ENABLE_PCINT */
|
|
|
|
ISR(INT0_vect, ISR_BLOCK)
|
|
{
|
|
irq_handler(0); /**< predefined interrupt pin */
|
|
}
|
|
|
|
ISR(INT1_vect, ISR_BLOCK)
|
|
{
|
|
irq_handler(1); /**< predefined interrupt pin */
|
|
}
|
|
|
|
#if defined(INT2_vect)
|
|
ISR(INT2_vect, ISR_BLOCK)
|
|
{
|
|
irq_handler(2); /**< predefined interrupt pin */
|
|
}
|
|
#endif
|
|
|
|
#if defined(INT3_vect)
|
|
ISR(INT3_vect, ISR_BLOCK)
|
|
{
|
|
irq_handler(3); /**< predefined interrupt pin */
|
|
}
|
|
#endif
|
|
|
|
#if defined(INT4_vect)
|
|
ISR(INT4_vect, ISR_BLOCK)
|
|
{
|
|
irq_handler(4); /**< predefined interrupt pin */
|
|
}
|
|
#endif
|
|
|
|
#if defined(INT5_vect)
|
|
ISR(INT5_vect, ISR_BLOCK)
|
|
{
|
|
irq_handler(5); /**< predefined interrupt pin */
|
|
}
|
|
#endif
|
|
|
|
#if defined(INT6_vect)
|
|
ISR(INT6_vect, ISR_BLOCK)
|
|
{
|
|
irq_handler(6); /**< predefined interrupt pin */
|
|
}
|
|
#endif
|
|
|
|
#if defined(INT7_vect)
|
|
ISR(INT7_vect, ISR_BLOCK)
|
|
{
|
|
irq_handler(7); /**< predefined interrupt pin */
|
|
}
|
|
#endif
|
|
|
|
#endif /* MODULE_PERIPH_GPIO_IRQ */
|