ODROID-M1/S: Refactoring to eliminate repeated operations, mechanisms for easy maintenance
Signed-off-by: Steve Jeong <steve@how2flow.net>
Change-Id: Ieef76b76baa387454a174332168bd20b6d3e659b
diff --git a/wiringPi/odroidm1.c b/wiringPi/odroidm1.c
index 01529f6..fe469cc 100644
--- a/wiringPi/odroidm1.c
+++ b/wiringPi/odroidm1.c
@@ -203,7 +203,7 @@
/*----------------------------------------------------------------------------*/
static int gpioToShiftRegBy32 (int pin);
static int gpioToShiftRegBy16 (int pin);
-static void setClkState (int pin, int state);
+static void setClkState (int bank, int state);
static int setIomuxMode (int pin, int mode);
/*----------------------------------------------------------------------------*/
// Function of pwm define
@@ -402,48 +402,22 @@
// set GPIO clock state
//
/*----------------------------------------------------------------------------*/
-__attribute__ ((unused))static void setClkState (int pin, int state)
+__attribute__ ((unused))static void setClkState (int bank, int state)
{
- uint32_t target = 0;
- uint8_t bank = (pin / GPIO_SIZE);
- uint8_t gpioPclkShift = (bank == 0 ? M1_PMU_CRU_GPIO_PCLK_BIT : (bank * M1_CRU_GPIO_PCLK_BIT));
+ uint32_t data, regOffset;
+ uint8_t gpioPclkShift;
- target |= (1 << (gpioPclkShift + 16));
+ gpioPclkShift = (bank == 0 ? M1_PMU_CRU_GPIO_PCLK_BIT : (bank * M1_CRU_GPIO_PCLK_BIT));
+ regOffset = M1_PMU_CRU_GPIO_CLK_OFFSET;
- switch (state) {
- case M1_CLK_ENABLE:
- if (bank == 0) {
- target |= *(cru[0] + M1_PMU_CRU_GPIO_CLK_OFFSET);
- target &= ~(1 << gpioPclkShift);
- *(cru[0] + M1_PMU_CRU_GPIO_CLK_OFFSET) = target;
- } else {
- target |= *(cru[1] + M1_CRU_GPIO_CLK_OFFSET);
- target &= ~(1 << gpioPclkShift);
- *(cru[1] + M1_CRU_GPIO_CLK_OFFSET) = target;
- }
- break;
- case M1_CLK_DISABLE:
- if (bank == 0) {
- target |= *(cru[0] + M1_PMU_CRU_GPIO_CLK_OFFSET);
- target |= (1 << gpioPclkShift);
- *(cru[0] + M1_PMU_CRU_GPIO_CLK_OFFSET) = target;
- } else {
- target |= *(cru[1] + M1_CRU_GPIO_CLK_OFFSET);
- target |= (1 << gpioPclkShift);
- *(cru[1] + M1_CRU_GPIO_CLK_OFFSET) = target;
- }
- break;
- case M1_CLK_BYTE_ENABLE:
- setClkState(GPIO_SIZE * 0, M1_CLK_ENABLE);
- setClkState(GPIO_SIZE * 3, M1_CLK_ENABLE);
- break;
- case M1_CLK_BYTE_DISABLE:
- setClkState(GPIO_SIZE * 0, M1_CLK_DISABLE);
- setClkState(GPIO_SIZE * 3, M1_CLK_DISABLE);
- break;
- default:
- break;
- }
+ // Once the final address/data of the register is determined, 'bank' is determined to be zero or not.
+ bank = (bank != 0);
+ data = *(cru[bank] + regOffset);
+
+ data &= ~(1 << gpioPclkShift);
+ data |= (state << gpioPclkShift);
+ data |= (1 << (gpioPclkShift + 16)); // write_mask
+ *(cru[bank] + regOffset) = data;
}
/*----------------------------------------------------------------------------*/
//
@@ -452,7 +426,7 @@
/*----------------------------------------------------------------------------*/
__attribute__ ((unused))static int setIomuxMode (int pin, int mode)
{
- uint32_t regOffset, target;
+ uint32_t data, regOffset;
uint8_t bank, group, bankOffset, groupOffset;
if (lib->mode == MODE_GPIO_SYS)
@@ -467,40 +441,18 @@
regOffset = (bank == 0 ? 0 : bank-1) * 0x8 + group * 0x2;
regOffset += (groupOffset / 4 == 0) ? 0x0 : 0x1;
+ regOffset += (bank == 0 ? M1_PMU_GRF_IOMUX_OFFSET : M1_SYS_GRF_IOMUX_OFFSET);
+
+ // Once the final address/data of the register is determined, 'bank' is determined to be zero or not.
+ bank = (bank != 0);
+ data = *(grf[bank] + regOffset);
// Common IOMUX Funtion 1 : GPIO (3'h0)
switch (mode) {
case M1_FUNC_GPIO: // Common IOMUX Function 1_GPIO (3'h0)
- if (bank == 0) {
- regOffset += M1_PMU_GRF_IOMUX_OFFSET;
- target = *(grf[0] + regOffset);
- target |= (0x7 << ((groupOffset % 4) * 4 + 16));
- target &= ~(0x7 << ((groupOffset % 4) * 4)); // ~0x07 = 3'h0
- *(grf[0] + regOffset) = target;
- }
- else {
- regOffset += M1_SYS_GRF_IOMUX_OFFSET;
- target = *(grf[1] + regOffset);
- target |= (0x7 << ((groupOffset % 4) * 4 + 16));
- target &= ~(0x7 << ((groupOffset % 4) * 4));
- *(grf[1] + regOffset) = target;
- }
- break;
- case M1_FUNC_PWM:
- if (bank == 0) {
- regOffset += M1_PMU_GRF_IOMUX_OFFSET;
- target = *(grf[0] + regOffset);
- target |= (0x7 << ((groupOffset % 4) * 4 + 16));
- target |= (0x4 << ((groupOffset % 4) * 4)); // gpio0 b5/b6: 3'h100
- *(grf[0] + regOffset) = target;
- }
- else {
- regOffset += M1_SYS_GRF_IOMUX_OFFSET;
- target = *(grf[1] + regOffset);
- target |= (0x7 << ((groupOffset % 4) * 4 + 16));
- target |= (0x5 << ((groupOffset % 4) * 4)); // gpio3 b2: 3'h101
- *(grf[1] + regOffset) = target;
- }
+ data &= ~(0x7 << ((groupOffset % 4) * 4)); // ~0x07 = 3'h0
+ data |= (0x7 << ((groupOffset % 4) * 4 + 16)); // write_mask
+ *(grf[bank] + regOffset) = data;
break;
default:
break;
@@ -511,7 +463,7 @@
/*----------------------------------------------------------------------------*/
__attribute__ ((unused))static int _pinMode (int pin, int mode)
{
- uint32_t regOffset, target;
+ uint32_t data, regOffset;
uint8_t bank, bankOffset;
int origPin;
@@ -531,45 +483,36 @@
softPwmStop(origPin);
softToneStop(origPin);
- target = *(gpio[bank] + regOffset);
- target |= (1 << (gpioToShiftRegBy16(pin) + 16));
+ setClkState(bank, M1_CLK_ENABLE);
+ setIomuxMode(origPin, M1_FUNC_GPIO);
+
+ data = *(gpio[bank] + regOffset);
switch (mode) {
- case INPUT:
- setIomuxMode(origPin, M1_FUNC_GPIO);
- target &= ~(1 << gpioToShiftRegBy16(pin));
- *(gpio[bank] + regOffset) = target;
- _pullUpDnControl(origPin, PUD_OFF);
- break;
- case OUTPUT:
- setIomuxMode(origPin, M1_FUNC_GPIO);
- target |= (1 << gpioToShiftRegBy16(pin));
- *(gpio[bank] + regOffset) = target;
- break;
- case INPUT_PULLUP:
- setIomuxMode(origPin, M1_FUNC_GPIO);
- target &= ~(1 << gpioToShiftRegBy16(pin));
- *(gpio[bank] + regOffset) = target;
- _pullUpDnControl(origPin, PUD_UP);
- break;
- case INPUT_PULLDOWN:
- setIomuxMode(origPin, M1_FUNC_GPIO);
- target &= ~(1 << gpioToShiftRegBy16(pin));
- *(gpio[bank] + regOffset) = target;
- _pullUpDnControl(origPin, PUD_DOWN);
- break;
- case SOFT_PWM_OUTPUT:
- softPwmCreate(origPin, 0, 100);
- break;
- case SOFT_TONE_OUTPUT:
- softToneCreate(origPin);
- break;
- case PWM_OUTPUT:
- pwmSetup(origPin);
- break;
- default:
- msg(MSG_WARN, "%s : Unknown Mode %d\n", __func__, mode);
- return -1;
+ case INPUT:
+ case INPUT_PULLUP:
+ case INPUT_PULLDOWN:
+ _pullUpDnControl(origPin, mode);
+ __attribute__((fallthrough));
+ case OUTPUT:
+ mode = (mode == OUTPUT);
+ data &= ~(1 << gpioToShiftRegBy16(pin));
+ data |=(mode << gpioToShiftRegBy16(pin));
+ data |= (1 << (gpioToShiftRegBy16(pin) + 16)); // write_mask
+ *(gpio[bank] + regOffset) = data;
+ break;
+ case SOFT_PWM_OUTPUT:
+ softPwmCreate(origPin, 0, 100);
+ break;
+ case SOFT_TONE_OUTPUT:
+ softToneCreate(origPin);
+ break;
+ case PWM_OUTPUT:
+ pwmSetup(origPin);
+ break;
+ default:
+ msg(MSG_WARN, "%s : Unknown Mode %d\n", __func__, mode);
+ break;
}
return 0;
@@ -611,12 +554,14 @@
switch (mode) {
case INPUT:
+ case INPUT_PULLUP:
+ case INPUT_PULLDOWN:
ret = gpiod_line_request_input(gpiod, CONSUMER);
if (ret < 0) {
printf("gpiod request error\n");
gpiod_line_release(gpiod);
}
- _pullUpDnControl(origPin, PUD_OFF);
+ _pullUpDnControl(origPin, mode);
break;
case OUTPUT:
ret = gpiod_line_request_output(gpiod, CONSUMER, 0);
@@ -625,22 +570,6 @@
gpiod_line_release(gpiod);
}
break;
- case INPUT_PULLUP:
- ret = gpiod_line_request_input(gpiod, CONSUMER);
- if (ret < 0) {
- printf("gpiod request error\n");
- gpiod_line_release(gpiod);
- }
- _pullUpDnControl(origPin, PUD_UP);
- break;
- case INPUT_PULLDOWN:
- ret = gpiod_line_request_input(gpiod, CONSUMER);
- if (ret < 0) {
- printf("gpiod request error\n");
- gpiod_line_release(gpiod);
- }
- _pullUpDnControl(origPin, PUD_DOWN);
- break;
case SOFT_PWM_OUTPUT:
softPwmCreate(origPin, 0, 100);
break;
@@ -662,7 +591,7 @@
/*----------------------------------------------------------------------------*/
__attribute__ ((unused))static int _getDrive(int pin)
{
- uint32_t regOffset, target;
+ uint32_t data, regOffset;
uint8_t bank, group, bankOffset, groupOffset;
int value = 0;
@@ -676,25 +605,18 @@
bankOffset = (pin - (bank * GPIO_SIZE));
group = (bankOffset / 8);
groupOffset = (pin % 8);
+ regOffset = (bank == 0 ? M1_PMU_GRF_DS_OFFSET : M1_SYS_GRF_DS_OFFSET + ((bank - 1) * 0x10));
+ regOffset += (group * 0x4);
+ regOffset += ((groupOffset / 2) * 0x1);
- if (bank == 0) {
- regOffset = M1_PMU_GRF_DS_OFFSET;
- regOffset += (group * 0x4);
- regOffset += ((groupOffset / 2) * 0x1);
- target = *(grf[0] + regOffset);
- }
- else {
- regOffset = M1_SYS_GRF_DS_OFFSET;
- regOffset += ((bank - 1) * 0x10);
- regOffset += (group * 0x4);
- regOffset += ((groupOffset / 2) * 0x1);
- target = *(grf[1] + regOffset);
- }
+ // Once the final address/data of the register is determined, 'bank' is determined to be zero or not.
+ bank = (bank != 0);
- target &= 0x3f3f; //reset reserved bits
- target = (groupOffset % 2 == 0 ? target & 0x3f : target >> 8);
+ data = *(grf[bank] + regOffset);
+ data &= 0x3f3f; //reset reserved bits
+ data = (groupOffset % 2 == 0 ? data & 0x3f : data >> 8);
- switch (target) {
+ switch (data) {
case DS_LEVEL_0:
value = 0;
break;
@@ -723,7 +645,7 @@
/*----------------------------------------------------------------------------*/
__attribute__ ((unused))static int _setDrive(int pin, int value)
{
- uint32_t regOffset, target;
+ uint32_t data, regOffset;
uint8_t bank, group, bankOffset, groupOffset;
if (lib->mode == MODE_GPIO_SYS)
@@ -736,53 +658,42 @@
bankOffset = (pin - (bank * GPIO_SIZE));
group = (bankOffset / 8);
groupOffset = (pin % 8);
+ regOffset = (bank == 0 ? M1_PMU_GRF_DS_OFFSET : M1_SYS_GRF_DS_OFFSET + ((bank - 1) * 0x10));
+ regOffset += (group * 0x4);
+ regOffset += ((groupOffset / 2) * 0x1);
- if (bank == 0) {
- regOffset = M1_PMU_GRF_DS_OFFSET;
- regOffset += (group * 0x4);
- regOffset += ((groupOffset / 2) * 0x1);
- target = *(grf[0] + regOffset);
- }
- else {
- regOffset = M1_SYS_GRF_DS_OFFSET;
- regOffset += ((bank - 1) * 0x10);
- regOffset += (group * 0x4);
- regOffset += ((groupOffset / 2) * 0x1);
- target = *(grf[1] + regOffset);
- }
+ // Once the final address/data of the register is determined, 'bank' is determined to be zero or not.
+ bank = (bank != 0);
- target |= (0x3f3f << 16);
- target &= ~(groupOffset % 2 == 0 ? 0x3f << 0 : 0x3f << 8);
+ data = *(grf[bank] + regOffset);
+ data |= (0x3f3f << 16);
+ data &= ~(groupOffset % 2 == 0 ? 0x3f << 0 : 0x3f << 8);
switch (value) {
case 0:
- target |= (groupOffset % 2 == 0 ? DS_LEVEL_0 : (DS_LEVEL_0 << 8));
+ data |= (groupOffset % 2 == 0 ? DS_LEVEL_0 : (DS_LEVEL_0 << 8));
break;
case 1:
- target |= (groupOffset % 2 == 0 ? DS_LEVEL_1 : (DS_LEVEL_1 << 8));
+ data |= (groupOffset % 2 == 0 ? DS_LEVEL_1 : (DS_LEVEL_1 << 8));
break;
case 2:
- target |= (groupOffset % 2 == 0 ? DS_LEVEL_2 : (DS_LEVEL_2 << 8));
+ data |= (groupOffset % 2 == 0 ? DS_LEVEL_2 : (DS_LEVEL_2 << 8));
break;
case 3:
- target |= (groupOffset % 2 == 0 ? DS_LEVEL_3 : (DS_LEVEL_3 << 8));
+ data |= (groupOffset % 2 == 0 ? DS_LEVEL_3 : (DS_LEVEL_3 << 8));
break;
case 4:
- target |= (groupOffset % 2 == 0 ? DS_LEVEL_4 : (DS_LEVEL_4 << 8));
+ data |= (groupOffset % 2 == 0 ? DS_LEVEL_4 : (DS_LEVEL_4 << 8));
break;
case 5:
- target |= (groupOffset % 2 == 0 ? DS_LEVEL_5 : (DS_LEVEL_5 << 8));
+ data |= (groupOffset % 2 == 0 ? DS_LEVEL_5 : (DS_LEVEL_5 << 8));
break;
default:
break;
}
- if (bank == 0) {
- *(grf[0] + regOffset) = target;
- }
- else {
- *(grf[1] + regOffset) = target;
- }
+ *(grf[bank] + regOffset) = data;
+
return 0;
}
/*----------------------------------------------------------------------------*/
@@ -813,14 +724,8 @@
// The shift to move to the target pin at the register
shift = groupOffset % 4 * 4;
- // Check if the pin is GPIO mode on GRF register
- if (bank == 0) {
- regOffset += M1_PMU_GRF_IOMUX_OFFSET; //0x00
- ret = (*(grf[0] + regOffset) >> shift) & 0x7;
- } else {
- regOffset += M1_SYS_GRF_IOMUX_OFFSET; //0x00
- ret = (*(grf[1] + regOffset) >> shift) & 0x7;
- }
+ regOffset += (bank == 0 ? M1_PMU_GRF_IOMUX_OFFSET : M1_SYS_GRF_IOMUX_OFFSET);
+ ret = (*(grf[(bank != 0)] + regOffset) >> shift) & 0x7;
// If it is ALT0 (GPIO mode), check it's direction
// Add regOffset 0x4 to go to H register
@@ -859,13 +764,12 @@
groupOffset = (pin % 8);
pupd = 0x00;
pupd = (0x3 << (groupOffset * 2));
- regOffset = (bank == 0) ? M1_PMU_GRF_PUPD_OFFSET + (group * 0x1) : M1_SYS_GRF_PUPD_OFFSET + (group * 0x1) + ((bank - 1) * 0x4);
+ regOffset = (bank == 0 ? M1_PMU_GRF_PUPD_OFFSET + (group * 0x1) : M1_SYS_GRF_PUPD_OFFSET + (group * 0x1) + ((bank - 1) * 0x4));
- if (bank == 0)
- pupd &= *(grf[0] + regOffset);
- else
- pupd &= *(grf[1] + regOffset);
+ // Once the final address/data of the register is determined, 'bank' is determined to be zero or not.
+ bank = (bank != 0);
+ pupd &= *(grf[bank] + regOffset);
pupd = (pupd >> groupOffset * 2);
return pupd;
@@ -873,7 +777,7 @@
/*----------------------------------------------------------------------------*/
__attribute__ ((unused))static int _pullUpDnControl (int pin, int pud)
{
- uint32_t regOffset, target;
+ uint32_t data, regOffset;
uint8_t bank, group, bankOffset, groupOffset;
if (lib->mode == MODE_GPIO_SYS)
@@ -888,63 +792,29 @@
groupOffset = (pin % 8);
regOffset = (bank == 0) ? M1_PMU_GRF_PUPD_OFFSET + (group * 0x1) : M1_SYS_GRF_PUPD_OFFSET + (group * 0x1) + ((bank - 1) * 0x4);
+ // Once the final address/data of the register is determined, 'bank' is determined to be zero or not.
+ bank = (bank != 0);
+
+ data = *(grf[bank] + regOffset);
+ data &= ~(0x3 << (groupOffset * 2));
+
switch (pud) {
case PUD_UP:
- if (bank == 0)
- {
- target = *(grf[0] + regOffset);
- target |= (0x3 << ((groupOffset * 2) + 16));
- target &= ~(0x3 << (groupOffset * 2));
- target |= (0x1 << (groupOffset * 2));
- *(grf[0] + regOffset) = target;
- }
- else
- {
- target = *(grf[1] + regOffset);
- target |= (0x3 << ((groupOffset * 2) + 16));
- target &= ~(0x3 << (groupOffset * 2));
- target |= (0x1 << (groupOffset * 2));
- *(grf[1] + regOffset) = target;
- }
+ data |= (0x1 << (groupOffset * 2));
break;
case PUD_DOWN:
- if (bank == 0)
- {
- target = *(grf[0] + regOffset);
- target |= (0x3 << ((groupOffset * 2) + 16));
- target &= ~(0x3 << (groupOffset * 2));
- target |= (0x2 << (groupOffset * 2));
- *(grf[0] + regOffset) = target;
- }
- else
- {
- target = *(grf[1] + regOffset);
- target |= (0x3 << ((groupOffset * 2) + 16));
- target &= ~(0x3 << (groupOffset * 2));
- target |= (0x2 << (groupOffset * 2));
- *(grf[1] + regOffset) = target;
- }
+ data |= (0x2 << (groupOffset * 2));
break;
case PUD_OFF:
- if (bank == 0)
- {
- target = *(grf[0] + regOffset);
- target |= (0x3 << ((groupOffset * 2) + 16));
- target &= ~(0x3 << (groupOffset * 2));
- *(grf[0] + regOffset) = target;
- }
- else
- {
- target = *(grf[1] + regOffset);
- target |= (0x3 << ((groupOffset * 2) + 16));
- target &= ~(0x3 << (groupOffset * 2));
- *(grf[1] + regOffset) = target;
- }
break;
default:
+ /* No message */
break;
}
+ data |= (0x3 << ((groupOffset * 2) + 16)); // write_mask
+ *(grf[bank] + regOffset) = data;
+
return 0;
}
/*----------------------------------------------------------------------------*/
@@ -1030,7 +900,7 @@
/*----------------------------------------------------------------------------*/
__attribute__ ((unused))static int _digitalWrite (int pin, int value)
{
- uint32_t regOffset, target;
+ uint32_t data, regOffset;
uint8_t bank, bankOffset;
if (lib->mode == MODE_GPIO_SYS) {
@@ -1055,24 +925,13 @@
bank = (pin / GPIO_SIZE);
bankOffset = (pin - (bank * GPIO_SIZE));
-
regOffset = (bankOffset / 16 == 0 ? M1_GPIO_SET_OFFSET : M1_GPIO_SET_OFFSET + 0x01);
- target = *(gpio[bank] + regOffset);
- target |= (1 << (gpioToShiftRegBy16(pin)+16));
-
- switch (value) {
- case LOW:
- target &= ~(1 << gpioToShiftRegBy16(pin));
- *(gpio[bank] + regOffset) = target;
- break;
- case HIGH:
- target |= (1 << gpioToShiftRegBy16(pin));
- *(gpio[bank] + regOffset) = target;
- break;
- default:
- break;
- }
+ data = *(gpio[bank] + regOffset);
+ data &= ~(1 << gpioToShiftRegBy16(pin));
+ data |= (value << gpioToShiftRegBy16(pin));
+ data |= (1 << (gpioToShiftRegBy16(pin) + 16)); // write_mask
+ *(gpio[bank] + regOffset) = data;
return 0;
}
@@ -1218,6 +1077,9 @@
return -1;
}
+ setClkState(GPIO_SIZE * 0, M1_CLK_ENABLE);
+ setClkState(GPIO_SIZE * 3, M1_CLK_ENABLE);
+
/* Read data register */
gpio0.wvalue = *(gpio[0] + M1_GPIO_GET_OFFSET);
gpio3.wvalue = *(gpio[3] + M1_GPIO_GET_OFFSET);
@@ -1326,6 +1188,9 @@
return -1;
}
+ setClkState(GPIO_SIZE * 0, M1_CLK_ENABLE);
+ setClkState(GPIO_SIZE * 3, M1_CLK_ENABLE);
+
/* Read data register */
gpio0.wvalue = *(gpio[0] + M1_GPIO_GET_OFFSET);
gpio3.wvalue = *(gpio[3] + M1_GPIO_GET_OFFSET);
diff --git a/wiringPi/odroidm1.h b/wiringPi/odroidm1.h
index 986c9b2..c3a91e3 100644
--- a/wiringPi/odroidm1.h
+++ b/wiringPi/odroidm1.h
@@ -33,26 +33,23 @@
//setClkState mode
#define M1_CLK_ENABLE 0
#define M1_CLK_DISABLE 1
-#define M1_CLK_BYTE_ENABLE 2
-#define M1_CLK_BYTE_DISABLE 3
#define M1_GRF_BLOCK_SIZE 0xFFFF
#define GPIO_SIZE 32
#define M1_FUNC_GPIO 0
-#define M1_FUNC_PWM 1
// GPIO[0]
#define M1_GPIO_0_BASE 0xFDD60000
// to control clock (PMU_CRU)
#define M1_PMU_CRU_BASE 0xFDD00000
-#define M1_PMU_CRU_GPIO_CLK_OFFSET 0x61 /* (0x184 >> 2) */
+#define M1_PMU_CRU_GPIO_CLK_OFFSET (0x184 >> 2)
#define M1_PMU_CRU_GPIO_PCLK_BIT 9
// to control IOMUX
#define M1_PMU_GRF_BASE 0xFDC20000
#define M1_PMU_GRF_IOMUX_OFFSET 0x00
-#define M1_PMU_GRF_PUPD_OFFSET 0x08 /* (0x20 >> 2) */
-#define M1_PMU_GRF_DS_OFFSET 0x1C /* (0x70 >> 2) */
+#define M1_PMU_GRF_PUPD_OFFSET (0x20 >> 2)
+#define M1_PMU_GRF_DS_OFFSET (0x70 >> 2)
// GPIO[1:4]
#define M1_GPIO_1_BASE 0xFE740000
@@ -61,18 +58,18 @@
#define M1_GPIO_4_BASE 0xFE770000
// to control clock (SYS_CRU)
#define M1_CRU_BASE 0xFDD20000
-#define M1_CRU_GPIO_CLK_OFFSET 0xDF /* (0x37c >> 2) */
+#define M1_CRU_GPIO_CLK_OFFSET (0x37c >> 2)
#define M1_CRU_GPIO_PCLK_BIT 2
// to control IOMUX
#define M1_SYS_GRF_BASE 0xFDC60000
#define M1_SYS_GRF_IOMUX_OFFSET 0x00
-#define M1_SYS_GRF_PUPD_OFFSET 0x20 /* (0x80 >> 2) */
-#define M1_SYS_GRF_DS_OFFSET 0x80 /* (0x200) >> 2 */
+#define M1_SYS_GRF_PUPD_OFFSET (0x80 >> 2)
+#define M1_SYS_GRF_DS_OFFSET (0x200 >> 2)
// Common offset for GPIO registers from each GPIO bank's base address
-#define M1_GPIO_DIR_OFFSET 0x02 /* (0x8) >> 2 */
+#define M1_GPIO_DIR_OFFSET (0x8 >> 2)
#define M1_GPIO_SET_OFFSET 0x00
-#define M1_GPIO_GET_OFFSET 0x1C /* (0x70 >> 2) */
+#define M1_GPIO_GET_OFFSET (0x70 >> 2)
// GPIO DS LEVELS
#define DS_LEVEL_0 0x01 //0b000001
diff --git a/wiringPi/odroidm1s.c b/wiringPi/odroidm1s.c
index f85a41c..5cfdc4e 100644
--- a/wiringPi/odroidm1s.c
+++ b/wiringPi/odroidm1s.c
@@ -208,7 +208,7 @@
/*----------------------------------------------------------------------------*/
static int gpioToShiftRegBy32 (int pin);
static int gpioToShiftRegBy16 (int pin);
-static void setClkState (int pin, int state);
+static void setClkState (int bank, int state);
static int setIomuxMode (int pin, int mode);
/*----------------------------------------------------------------------------*/
// Function of pwm define
@@ -404,48 +404,22 @@
// set GPIO clock state
//
/*----------------------------------------------------------------------------*/
-__attribute__ ((unused))static void setClkState (int pin, int state)
+__attribute__ ((unused))static void setClkState (int bank, int state)
{
- uint32_t target = 0;
- uint8_t bank = (pin / GPIO_SIZE);
- uint8_t gpioPclkShift = (bank == 0 ? M1_PMU_CRU_GPIO_PCLK_BIT : (bank * M1_CRU_GPIO_PCLK_BIT));
+ uint32_t data, regOffset;
+ uint8_t gpioPclkShift;
- target |= (1 << (gpioPclkShift + 16));
+ gpioPclkShift = (bank == 0 ? M1_PMU_CRU_GPIO_PCLK_BIT : (bank * M1_CRU_GPIO_PCLK_BIT));
+ regOffset = M1_PMU_CRU_GPIO_CLK_OFFSET;
- switch (state) {
- case M1_CLK_ENABLE:
- if (bank == 0) {
- target |= *(cru[0] + M1_PMU_CRU_GPIO_CLK_OFFSET);
- target &= ~(1 << gpioPclkShift);
- *(cru[0] + M1_PMU_CRU_GPIO_CLK_OFFSET) = target;
- } else {
- target |= *(cru[1] + M1_CRU_GPIO_CLK_OFFSET);
- target &= ~(1 << gpioPclkShift);
- *(cru[1] + M1_CRU_GPIO_CLK_OFFSET) = target;
- }
- break;
- case M1_CLK_DISABLE:
- if (bank == 0) {
- target |= *(cru[0] + M1_PMU_CRU_GPIO_CLK_OFFSET);
- target |= (1 << gpioPclkShift);
- *(cru[0] + M1_PMU_CRU_GPIO_CLK_OFFSET) = target;
- } else {
- target |= *(cru[1] + M1_CRU_GPIO_CLK_OFFSET);
- target |= (1 << gpioPclkShift);
- *(cru[1] + M1_CRU_GPIO_CLK_OFFSET) = target;
- }
- break;
- case M1_CLK_BYTE_ENABLE:
- setClkState(GPIO_SIZE * 0, M1_CLK_ENABLE);
- setClkState(GPIO_SIZE * 3, M1_CLK_ENABLE);
- break;
- case M1_CLK_BYTE_DISABLE:
- setClkState(GPIO_SIZE * 0, M1_CLK_DISABLE);
- setClkState(GPIO_SIZE * 3, M1_CLK_DISABLE);
- break;
- default:
- break;
- }
+ // Once the final address/data of the register is determined, 'bank' is determined to be zero or not.
+ bank = (bank != 0);
+ data = *(cru[bank] + regOffset);
+
+ data &= ~(1 << gpioPclkShift);
+ data |= (state << gpioPclkShift);
+ data |= (1 << (gpioPclkShift + 16)); // write_mask
+ *(cru[bank] + regOffset) = data;
}
/*----------------------------------------------------------------------------*/
//
@@ -454,7 +428,7 @@
/*----------------------------------------------------------------------------*/
__attribute__ ((unused))static int setIomuxMode (int pin, int mode)
{
- uint32_t regOffset, target;
+ uint32_t data, regOffset;
uint8_t bank, group, bankOffset, groupOffset;
if (lib->mode == MODE_GPIO_SYS)
@@ -469,40 +443,18 @@
regOffset = (bank == 0 ? 0 : bank-1) * 0x8 + group * 0x2;
regOffset += (groupOffset / 4 == 0) ? 0x0 : 0x1;
+ regOffset += (bank == 0 ? M1_PMU_GRF_IOMUX_OFFSET : M1_SYS_GRF_IOMUX_OFFSET);
+
+ // Once the final address/data of the register is determined, 'bank' is determined to be zero or not.
+ bank = (bank != 0);
+ data = *(grf[bank] + regOffset);
// Common IOMUX Funtion 1 : GPIO (3'h0)
switch (mode) {
case M1_FUNC_GPIO: // Common IOMUX Function 1_GPIO (3'h0)
- if (bank == 0) {
- regOffset += M1_PMU_GRF_IOMUX_OFFSET;
- target = *(grf[0] + regOffset);
- target |= (0x7 << ((groupOffset % 4) * 4 + 16));
- target &= ~(0x7 << ((groupOffset % 4) * 4)); // ~0x07 = 3'h0
- *(grf[0] + regOffset) = target;
- }
- else {
- regOffset += M1_SYS_GRF_IOMUX_OFFSET;
- target = *(grf[1] + regOffset);
- target |= (0x7 << ((groupOffset % 4) * 4 + 16));
- target &= ~(0x7 << ((groupOffset % 4) * 4));
- *(grf[1] + regOffset) = target;
- }
- break;
- case M1_FUNC_PWM:
- if (bank == 0) {
- regOffset += M1_PMU_GRF_IOMUX_OFFSET;
- target = *(grf[0] + regOffset);
- target |= (0x7 << ((groupOffset % 4) * 4 + 16));
- target |= (0x4 << ((groupOffset % 4) * 4)); // gpio0 b5/b6: 3'h100
- *(grf[0] + regOffset) = target;
- }
- else {
- regOffset += M1_SYS_GRF_IOMUX_OFFSET;
- target = *(grf[1] + regOffset);
- target |= (0x7 << ((groupOffset % 4) * 4 + 16));
- target |= (0x5 << ((groupOffset % 4) * 4)); // gpio3 b2: 3'h101
- *(grf[1] + regOffset) = target;
- }
+ data &= ~(0x7 << ((groupOffset % 4) * 4)); // ~0x07 = 3'h0
+ data |= (0x7 << ((groupOffset % 4) * 4 + 16)); // write_mask
+ *(grf[bank] + regOffset) = data;
break;
default:
break;
@@ -513,7 +465,7 @@
/*----------------------------------------------------------------------------*/
__attribute__ ((unused))static int _pinMode (int pin, int mode)
{
- uint32_t regOffset, target;
+ uint32_t data, regOffset;
uint8_t bank, bankOffset;
int origPin;
@@ -533,45 +485,36 @@
softPwmStop(origPin);
softToneStop(origPin);
- target = *(gpio[bank] + regOffset);
- target |= (1 << (gpioToShiftRegBy16(pin) + 16));
+ setClkState(bank, M1_CLK_ENABLE);
+ setIomuxMode(origPin, M1_FUNC_GPIO);
+
+ data = *(gpio[bank] + regOffset);
switch (mode) {
- case INPUT:
- setIomuxMode(origPin, M1_FUNC_GPIO);
- target &= ~(1 << gpioToShiftRegBy16(pin));
- *(gpio[bank] + regOffset) = target;
- _pullUpDnControl(origPin, PUD_OFF);
- break;
- case OUTPUT:
- setIomuxMode(origPin, M1_FUNC_GPIO);
- target |= (1 << gpioToShiftRegBy16(pin));
- *(gpio[bank] + regOffset) = target;
- break;
- case INPUT_PULLUP:
- setIomuxMode(origPin, M1_FUNC_GPIO);
- target &= ~(1 << gpioToShiftRegBy16(pin));
- *(gpio[bank] + regOffset) = target;
- _pullUpDnControl(origPin, PUD_UP);
- break;
- case INPUT_PULLDOWN:
- setIomuxMode(origPin, M1_FUNC_GPIO);
- target &= ~(1 << gpioToShiftRegBy16(pin));
- *(gpio[bank] + regOffset) = target;
- _pullUpDnControl(origPin, PUD_DOWN);
- break;
- case SOFT_PWM_OUTPUT:
- softPwmCreate(origPin, 0, 100);
- break;
- case SOFT_TONE_OUTPUT:
- softToneCreate(origPin);
- break;
- case PWM_OUTPUT:
- pwmSetup(origPin);
- break;
- default:
- msg(MSG_WARN, "%s : Unknown Mode %d\n", __func__, mode);
- return -1;
+ case INPUT:
+ case INPUT_PULLUP:
+ case INPUT_PULLDOWN:
+ _pullUpDnControl(origPin, mode);
+ __attribute__((fallthrough));
+ case OUTPUT:
+ mode = (mode == OUTPUT);
+ data &= ~(1 << gpioToShiftRegBy16(pin));
+ data |=(mode << gpioToShiftRegBy16(pin));
+ data |= (1 << (gpioToShiftRegBy16(pin) + 16)); // write_mask
+ *(gpio[bank] + regOffset) = data;
+ break;
+ case SOFT_PWM_OUTPUT:
+ softPwmCreate(origPin, 0, 100);
+ break;
+ case SOFT_TONE_OUTPUT:
+ softToneCreate(origPin);
+ break;
+ case PWM_OUTPUT:
+ pwmSetup(origPin);
+ break;
+ default:
+ msg(MSG_WARN, "%s : Unknown Mode %d\n", __func__, mode);
+ break;
}
return 0;
@@ -613,12 +556,14 @@
switch (mode) {
case INPUT:
+ case INPUT_PULLUP:
+ case INPUT_PULLDOWN:
ret = gpiod_line_request_input(gpiod, CONSUMER);
if (ret < 0) {
printf("gpiod request error\n");
gpiod_line_release(gpiod);
}
- _pullUpDnControl(origPin, PUD_OFF);
+ _pullUpDnControl(origPin, mode);
break;
case OUTPUT:
ret = gpiod_line_request_output(gpiod, CONSUMER, 0);
@@ -627,22 +572,6 @@
gpiod_line_release(gpiod);
}
break;
- case INPUT_PULLUP:
- ret = gpiod_line_request_input(gpiod, CONSUMER);
- if (ret < 0) {
- printf("gpiod request error\n");
- gpiod_line_release(gpiod);
- }
- _pullUpDnControl(origPin, PUD_UP);
- break;
- case INPUT_PULLDOWN:
- ret = gpiod_line_request_input(gpiod, CONSUMER);
- if (ret < 0) {
- printf("gpiod request error\n");
- gpiod_line_release(gpiod);
- }
- _pullUpDnControl(origPin, PUD_DOWN);
- break;
case SOFT_PWM_OUTPUT:
softPwmCreate(origPin, 0, 100);
break;
@@ -664,7 +593,7 @@
/*----------------------------------------------------------------------------*/
__attribute__ ((unused))static int _getDrive(int pin)
{
- uint32_t regOffset, target;
+ uint32_t data, regOffset;
uint8_t bank, group, bankOffset, groupOffset;
int value = 0;
@@ -678,25 +607,18 @@
bankOffset = (pin - (bank * GPIO_SIZE));
group = (bankOffset / 8);
groupOffset = (pin % 8);
+ regOffset = (bank == 0 ? M1_PMU_GRF_DS_OFFSET : M1_SYS_GRF_DS_OFFSET + ((bank - 1) * 0x10));
+ regOffset += (group * 0x4);
+ regOffset += ((groupOffset / 2) * 0x1);
- if (bank == 0) {
- regOffset = M1_PMU_GRF_DS_OFFSET;
- regOffset += (group * 0x4);
- regOffset += ((groupOffset / 2) * 0x1);
- target = *(grf[0] + regOffset);
- }
- else {
- regOffset = M1_SYS_GRF_DS_OFFSET;
- regOffset += ((bank - 1) * 0x10);
- regOffset += (group * 0x4);
- regOffset += ((groupOffset / 2) * 0x1);
- target = *(grf[1] + regOffset);
- }
+ // Once the final address/data of the register is determined, 'bank' is determined to be zero or not.
+ bank = (bank != 0);
- target &= 0x3f3f; //reset reserved bits
- target = (groupOffset % 2 == 0 ? target & 0x3f : target >> 8);
+ data = *(grf[bank] + regOffset);
+ data &= 0x3f3f; //reset reserved bits
+ data = (groupOffset % 2 == 0 ? data & 0x3f : data >> 8);
- switch (target) {
+ switch (data) {
case DS_LEVEL_0:
value = 0;
break;
@@ -725,7 +647,7 @@
/*----------------------------------------------------------------------------*/
__attribute__ ((unused))static int _setDrive(int pin, int value)
{
- uint32_t regOffset, target;
+ uint32_t data, regOffset;
uint8_t bank, group, bankOffset, groupOffset;
if (lib->mode == MODE_GPIO_SYS)
@@ -738,53 +660,42 @@
bankOffset = (pin - (bank * GPIO_SIZE));
group = (bankOffset / 8);
groupOffset = (pin % 8);
+ regOffset = (bank == 0 ? M1_PMU_GRF_DS_OFFSET : M1_SYS_GRF_DS_OFFSET + ((bank - 1) * 0x10));
+ regOffset += (group * 0x4);
+ regOffset += ((groupOffset / 2) * 0x1);
- if (bank == 0) {
- regOffset = M1_PMU_GRF_DS_OFFSET;
- regOffset += (group * 0x4);
- regOffset += ((groupOffset / 2) * 0x1);
- target = *(grf[0] + regOffset);
- }
- else {
- regOffset = M1_SYS_GRF_DS_OFFSET;
- regOffset += ((bank - 1) * 0x10);
- regOffset += (group * 0x4);
- regOffset += ((groupOffset / 2) * 0x1);
- target = *(grf[1] + regOffset);
- }
+ // Once the final address/data of the register is determined, 'bank' is determined to be zero or not.
+ bank = (bank != 0);
- target |= (0x3f3f << 16);
- target &= ~(groupOffset % 2 == 0 ? 0x3f << 0 : 0x3f << 8);
+ data = *(grf[bank] + regOffset);
+ data |= (0x3f3f << 16);
+ data &= ~(groupOffset % 2 == 0 ? 0x3f << 0 : 0x3f << 8);
switch (value) {
case 0:
- target |= (groupOffset % 2 == 0 ? DS_LEVEL_0 : (DS_LEVEL_0 << 8));
+ data |= (groupOffset % 2 == 0 ? DS_LEVEL_0 : (DS_LEVEL_0 << 8));
break;
case 1:
- target |= (groupOffset % 2 == 0 ? DS_LEVEL_1 : (DS_LEVEL_1 << 8));
+ data |= (groupOffset % 2 == 0 ? DS_LEVEL_1 : (DS_LEVEL_1 << 8));
break;
case 2:
- target |= (groupOffset % 2 == 0 ? DS_LEVEL_2 : (DS_LEVEL_2 << 8));
+ data |= (groupOffset % 2 == 0 ? DS_LEVEL_2 : (DS_LEVEL_2 << 8));
break;
case 3:
- target |= (groupOffset % 2 == 0 ? DS_LEVEL_3 : (DS_LEVEL_3 << 8));
+ data |= (groupOffset % 2 == 0 ? DS_LEVEL_3 : (DS_LEVEL_3 << 8));
break;
case 4:
- target |= (groupOffset % 2 == 0 ? DS_LEVEL_4 : (DS_LEVEL_4 << 8));
+ data |= (groupOffset % 2 == 0 ? DS_LEVEL_4 : (DS_LEVEL_4 << 8));
break;
case 5:
- target |= (groupOffset % 2 == 0 ? DS_LEVEL_5 : (DS_LEVEL_5 << 8));
+ data |= (groupOffset % 2 == 0 ? DS_LEVEL_5 : (DS_LEVEL_5 << 8));
break;
default:
break;
}
- if (bank == 0) {
- *(grf[0] + regOffset) = target;
- }
- else {
- *(grf[1] + regOffset) = target;
- }
+ *(grf[bank] + regOffset) = data;
+
return 0;
}
/*----------------------------------------------------------------------------*/
@@ -815,14 +726,8 @@
// The shift to move to the target pin at the register
shift = groupOffset % 4 * 4;
- // Check if the pin is GPIO mode on GRF register
- if (bank == 0) {
- regOffset += M1_PMU_GRF_IOMUX_OFFSET; //0x00
- ret = (*(grf[0] + regOffset) >> shift) & 0x7;
- } else {
- regOffset += M1_SYS_GRF_IOMUX_OFFSET; //0x00
- ret = (*(grf[1] + regOffset) >> shift) & 0x7;
- }
+ regOffset += (bank == 0 ? M1_PMU_GRF_IOMUX_OFFSET : M1_SYS_GRF_IOMUX_OFFSET);
+ ret = (*(grf[(bank != 0)] + regOffset) >> shift) & 0x7;
// If it is ALT0 (GPIO mode), check it's direction
// Add regOffset 0x4 to go to H register
@@ -861,13 +766,12 @@
groupOffset = (pin % 8);
pupd = 0x00;
pupd = (0x3 << (groupOffset * 2));
- regOffset = (bank == 0) ? M1_PMU_GRF_PUPD_OFFSET + (group * 0x1) : M1_SYS_GRF_PUPD_OFFSET + (group * 0x1) + ((bank - 1) * 0x4);
+ regOffset = (bank == 0 ? M1_PMU_GRF_PUPD_OFFSET + (group * 0x1) : M1_SYS_GRF_PUPD_OFFSET + (group * 0x1) + ((bank - 1) * 0x4));
- if (bank == 0)
- pupd &= *(grf[0] + regOffset);
- else
- pupd &= *(grf[1] + regOffset);
+ // Once the final address/data of the register is determined, 'bank' is determined to be zero or not.
+ bank = (bank != 0);
+ pupd &= *(grf[bank] + regOffset);
pupd = (pupd >> groupOffset * 2);
return pupd;
@@ -875,7 +779,7 @@
/*----------------------------------------------------------------------------*/
__attribute__ ((unused))static int _pullUpDnControl (int pin, int pud)
{
- uint32_t regOffset, target;
+ uint32_t data, regOffset;
uint8_t bank, group, bankOffset, groupOffset;
if (lib->mode == MODE_GPIO_SYS)
@@ -890,63 +794,29 @@
groupOffset = (pin % 8);
regOffset = (bank == 0) ? M1_PMU_GRF_PUPD_OFFSET + (group * 0x1) : M1_SYS_GRF_PUPD_OFFSET + (group * 0x1) + ((bank - 1) * 0x4);
+ // Once the final address/data of the register is determined, 'bank' is determined to be zero or not.
+ bank = (bank != 0);
+
+ data = *(grf[bank] + regOffset);
+ data &= ~(0x3 << (groupOffset * 2));
+
switch (pud) {
case PUD_UP:
- if (bank == 0)
- {
- target = *(grf[0] + regOffset);
- target |= (0x3 << ((groupOffset * 2) + 16));
- target &= ~(0x3 << (groupOffset * 2));
- target |= (0x1 << (groupOffset * 2));
- *(grf[0] + regOffset) = target;
- }
- else
- {
- target = *(grf[1] + regOffset);
- target |= (0x3 << ((groupOffset * 2) + 16));
- target &= ~(0x3 << (groupOffset * 2));
- target |= (0x1 << (groupOffset * 2));
- *(grf[1] + regOffset) = target;
- }
+ data |= (0x1 << (groupOffset * 2));
break;
case PUD_DOWN:
- if (bank == 0)
- {
- target = *(grf[0] + regOffset);
- target |= (0x3 << ((groupOffset * 2) + 16));
- target &= ~(0x3 << (groupOffset * 2));
- target |= (0x2 << (groupOffset * 2));
- *(grf[0] + regOffset) = target;
- }
- else
- {
- target = *(grf[1] + regOffset);
- target |= (0x3 << ((groupOffset * 2) + 16));
- target &= ~(0x3 << (groupOffset * 2));
- target |= (0x2 << (groupOffset * 2));
- *(grf[1] + regOffset) = target;
- }
+ data |= (0x2 << (groupOffset * 2));
break;
case PUD_OFF:
- if (bank == 0)
- {
- target = *(grf[0] + regOffset);
- target |= (0x3 << ((groupOffset * 2) + 16));
- target &= ~(0x3 << (groupOffset * 2));
- *(grf[0] + regOffset) = target;
- }
- else
- {
- target = *(grf[1] + regOffset);
- target |= (0x3 << ((groupOffset * 2) + 16));
- target &= ~(0x3 << (groupOffset * 2));
- *(grf[1] + regOffset) = target;
- }
break;
default:
+ /* No message */
break;
}
+ data |= (0x3 << ((groupOffset * 2) + 16)); // write_mask
+ *(grf[bank] + regOffset) = data;
+
return 0;
}
/*----------------------------------------------------------------------------*/
@@ -1032,7 +902,7 @@
/*----------------------------------------------------------------------------*/
__attribute__ ((unused))static int _digitalWrite (int pin, int value)
{
- uint32_t regOffset, target;
+ uint32_t data, regOffset;
uint8_t bank, bankOffset;
if (lib->mode == MODE_GPIO_SYS) {
@@ -1057,24 +927,13 @@
bank = (pin / GPIO_SIZE);
bankOffset = (pin - (bank * GPIO_SIZE));
-
regOffset = (bankOffset / 16 == 0 ? M1_GPIO_SET_OFFSET : M1_GPIO_SET_OFFSET + 0x01);
- target = *(gpio[bank] + regOffset);
- target |= (1 << (gpioToShiftRegBy16(pin)+16));
-
- switch (value) {
- case LOW:
- target &= ~(1 << gpioToShiftRegBy16(pin));
- *(gpio[bank] + regOffset) = target;
- break;
- case HIGH:
- target |= (1 << gpioToShiftRegBy16(pin));
- *(gpio[bank] + regOffset) = target;
- break;
- default:
- break;
- }
+ data = *(gpio[bank] + regOffset);
+ data &= ~(1 << gpioToShiftRegBy16(pin));
+ data |= (value << gpioToShiftRegBy16(pin));
+ data |= (1 << (gpioToShiftRegBy16(pin) + 16)); // write_mask
+ *(gpio[bank] + regOffset) = data;
return 0;
}
@@ -1220,6 +1079,9 @@
return -1;
}
+ setClkState(GPIO_SIZE * 0, M1_CLK_ENABLE);
+ setClkState(GPIO_SIZE * 3, M1_CLK_ENABLE);
+
/* Read data register */
gpio0.wvalue = *(gpio[0] + M1_GPIO_GET_OFFSET);
gpio3.wvalue = *(gpio[3] + M1_GPIO_GET_OFFSET);
@@ -1328,6 +1190,9 @@
return -1;
}
+ setClkState(GPIO_SIZE * 0, M1_CLK_ENABLE);
+ setClkState(GPIO_SIZE * 3, M1_CLK_ENABLE);
+
/* Read data register */
gpio0.wvalue = *(gpio[0] + M1_GPIO_GET_OFFSET);
gpio3.wvalue = *(gpio[3] + M1_GPIO_GET_OFFSET);
diff --git a/wiringPi/wiringPi.h b/wiringPi/wiringPi.h
index 37aba34..eb51541 100644
--- a/wiringPi/wiringPi.h
+++ b/wiringPi/wiringPi.h
@@ -90,9 +90,9 @@
#define HIGH 1
// Pull up/down/none
-#define PUD_OFF 0
-#define PUD_DOWN 1
-#define PUD_UP 2
+#define PUD_OFF INPUT
+#define PUD_DOWN INPUT_PULLDOWN
+#define PUD_UP INPUT_PULLUP
// Interrupt levels
#define INT_EDGE_SETUP 0