Add esp/gpio_regs.h
This commit is contained in:
		
							parent
							
								
									9727df5f6c
								
							
						
					
					
						commit
						7fa2817f1b
					
				
					 6 changed files with 167 additions and 114 deletions
				
			
		|  | @ -9,7 +9,7 @@ | |||
| #ifndef _ESP_GPIO_H | ||||
| #define _ESP_GPIO_H | ||||
| #include <stdbool.h> | ||||
| #include "esp/registers.h" | ||||
| #include "esp/gpio_regs.h" | ||||
| #include "esp/iomux.h" | ||||
| #include "esp/cpu.h" | ||||
| #include "xtensa_interrupts.h" | ||||
|  | @ -32,26 +32,27 @@ INLINED void gpio_enable(const uint8_t gpio_num, const gpio_direction_t directio | |||
|     switch(direction) { | ||||
|     case GPIO_INPUT: | ||||
|         iomux_flags = 0; | ||||
|         ctrl_val = GPIO_SOURCE_GPIO; | ||||
|         ctrl_val = 0; | ||||
|         break; | ||||
|     case GPIO_OUTPUT: | ||||
|         iomux_flags = IOMUX_PIN_OUTPUT_ENABLE; | ||||
|         ctrl_val = GPIO_DRIVE_PUSH_PULL|GPIO_SOURCE_GPIO; | ||||
|         ctrl_val = GPIO_CONF_DRIVER_ENABLE; | ||||
|         break; | ||||
|     case GPIO_OUT_OPEN_DRAIN: | ||||
|         iomux_flags = IOMUX_PIN_OUTPUT_ENABLE; | ||||
|         ctrl_val = GPIO_DRIVE_OPEN_DRAIN|GPIO_SOURCE_GPIO; | ||||
|         ctrl_val = 0; | ||||
|         break; | ||||
|     case GPIO_INPUT_PULLUP: | ||||
|         iomux_flags = IOMUX_PIN_PULLUP; | ||||
|         ctrl_val = GPIO_SOURCE_GPIO; | ||||
|         ctrl_val = 0; | ||||
|         break; | ||||
|     } | ||||
|     iomux_set_gpio_function(gpio_num, iomux_flags); | ||||
|     GPIO_CTRL_REG(gpio_num) = (GPIO_CTRL_REG(gpio_num)&GPIO_INT_MASK) | ctrl_val; | ||||
|     if(direction == GPIO_OUTPUT) | ||||
|         GPIO_DIR_SET = BIT(gpio_num); | ||||
|     GPIO.CONF[gpio_num] = (GPIO.CONF[gpio_num] & FIELD_MASK(GPIO_CONF_INTTYPE)) | ctrl_val; | ||||
|     if (iomux_flags & IOMUX_PIN_OUTPUT_ENABLE) | ||||
|         GPIO.ENABLE_OUT_SET = BIT(gpio_num); | ||||
|     else | ||||
|         GPIO_DIR_CLEAR = BIT(gpio_num); | ||||
|         GPIO.ENABLE_OUT_CLEAR = BIT(gpio_num); | ||||
| } | ||||
| 
 | ||||
| /* Disable GPIO on the specified pin, and set it Hi-Z.
 | ||||
|  | @ -61,7 +62,7 @@ INLINED void gpio_enable(const uint8_t gpio_num, const gpio_direction_t directio | |||
|  */ | ||||
| INLINED void gpio_disable(const uint8_t gpio_num) | ||||
| { | ||||
|     GPIO_DIR_CLEAR = BIT(gpio_num); | ||||
|     GPIO.ENABLE_OUT_CLEAR = BIT(gpio_num); | ||||
|     *gpio_iomux_reg(gpio_num) &= ~IOMUX_PIN_OUTPUT_ENABLE; | ||||
| } | ||||
| 
 | ||||
|  | @ -72,9 +73,9 @@ INLINED void gpio_disable(const uint8_t gpio_num) | |||
| INLINED void gpio_write(const uint8_t gpio_num, const bool set) | ||||
| { | ||||
|     if(set) | ||||
|         GPIO_OUT_SET = BIT(gpio_num); | ||||
|         GPIO.OUT_SET = BIT(gpio_num); | ||||
|     else | ||||
|         GPIO_OUT_CLEAR = BIT(gpio_num); | ||||
|         GPIO.OUT_CLEAR = BIT(gpio_num); | ||||
| } | ||||
| 
 | ||||
| /* Toggle output of a pin
 | ||||
|  | @ -89,10 +90,10 @@ INLINED void gpio_toggle(const uint8_t gpio_num) | |||
|        get an invalid value. Prevents one task from clobbering another | ||||
|        task's pins, without needing to disable/enable interrupts. | ||||
|     */ | ||||
|     if(GPIO_OUT_REG & BIT(gpio_num)) | ||||
|         GPIO_OUT_CLEAR = BIT(gpio_num); | ||||
|     if(GPIO.OUT & BIT(gpio_num)) | ||||
|         GPIO.OUT_CLEAR = BIT(gpio_num); | ||||
|     else | ||||
|         GPIO_OUT_SET = BIT(gpio_num); | ||||
|         GPIO.OUT_SET = BIT(gpio_num); | ||||
| } | ||||
| 
 | ||||
| /* Read input value of a GPIO pin.
 | ||||
|  | @ -102,38 +103,28 @@ INLINED void gpio_toggle(const uint8_t gpio_num) | |||
|  */ | ||||
| INLINED bool gpio_read(const uint8_t gpio_num) | ||||
| { | ||||
|     return GPIO_IN_REG & BIT(gpio_num); | ||||
|     return GPIO.IN & BIT(gpio_num); | ||||
| } | ||||
| 
 | ||||
| typedef enum { | ||||
|     INT_NONE = 0, | ||||
|     INT_RISING = GPIO_INT_RISING, | ||||
|     INT_FALLING = GPIO_INT_FALLING, | ||||
|     INT_CHANGE = GPIO_INT_CHANGE, | ||||
|     INT_LOW = GPIO_INT_LOW, | ||||
|     INT_HIGH = GPIO_INT_HIGH, | ||||
| } gpio_interrupt_t; | ||||
| 
 | ||||
| extern void gpio_interrupt_handler(void); | ||||
| 
 | ||||
| /* Set the interrupt type for a given pin
 | ||||
|  * | ||||
|  * If int_type is not INT_NONE, the gpio_interrupt_handler will be attached and unmasked. | ||||
|  * If int_type is not GPIO_INTTYPE_NONE, the gpio_interrupt_handler will be attached and unmasked. | ||||
|  */ | ||||
| INLINED void gpio_set_interrupt(const uint8_t gpio_num, const gpio_interrupt_t int_type) | ||||
| INLINED void gpio_set_interrupt(const uint8_t gpio_num, const gpio_inttype_t int_type) | ||||
| { | ||||
|     GPIO_CTRL_REG(gpio_num) = (GPIO_CTRL_REG(gpio_num)&~GPIO_INT_MASK) | ||||
|         | (int_type & GPIO_INT_MASK); | ||||
|     if(int_type != INT_NONE) { | ||||
|     GPIO.CONF[gpio_num] = SET_FIELD(GPIO.CONF[gpio_num], GPIO_CONF_INTTYPE, int_type); | ||||
|     if(int_type != GPIO_INTTYPE_NONE) { | ||||
|         _xt_isr_attach(INUM_GPIO, gpio_interrupt_handler); | ||||
|         _xt_isr_unmask(1<<INUM_GPIO); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /* Return the interrupt type set for a pin */ | ||||
| INLINED gpio_interrupt_t gpio_get_interrupt(const uint8_t gpio_num) | ||||
| INLINED gpio_inttype_t gpio_get_interrupt(const uint8_t gpio_num) | ||||
| { | ||||
|     return (gpio_interrupt_t)(GPIO_CTRL_REG(gpio_num) & GPIO_INT_MASK); | ||||
|     return FIELD2VAL(GPIO_CONF_INTTYPE, GPIO.CONF[gpio_num]); | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
							
								
								
									
										133
									
								
								core/include/esp/gpio_regs.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								core/include/esp/gpio_regs.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,133 @@ | |||
| /* esp/iomux_regs.h
 | ||||
|  * | ||||
|  * ESP8266 GPIO register definitions | ||||
|  * | ||||
|  * Not compatible with ESP SDK register access code. | ||||
|  */ | ||||
| 
 | ||||
| #ifndef _ESP_GPIO_REGS_H | ||||
| #define _ESP_GPIO_REGS_H | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| #include "common_macros.h" | ||||
| 
 | ||||
| #define GPIO_BASE 0x60000300 | ||||
| #define GPIO (*(struct GPIO_REGS *)(GPIO_BASE)) | ||||
| 
 | ||||
| /** GPIO output registers GPIO.OUT, GPIO.OUT_SET, GPIO.OUT_CLEAR:
 | ||||
|  * | ||||
|  * _SET and _CLEAR write-only registers set and clear bits in the main register, | ||||
|  * respectively. | ||||
|  * | ||||
|  * i.e. | ||||
|  *   GPIO.OUT_SET = BIT(3); | ||||
|  * and | ||||
|  *   GPIO.OUT |= BIT(3); | ||||
|  * | ||||
|  * ... are equivalent, but the former uses fewer CPU cycles. | ||||
|  * | ||||
|  * ENABLE_OUT / ENABLE_OUT_SET / ENABLE_OUT_CLEAR: | ||||
|  * | ||||
|  * Determine whether the corresponding GPIO has its output enabled or not. | ||||
|  * When clear, GPIO can function as an input.  When set, GPIO will drive its | ||||
|  * output (and IN register will simply reflect the output state). | ||||
|  * | ||||
|  * (_SET/_CLEAR function similarly to OUT registers) | ||||
|  * | ||||
|  * STATUS / STATUS_SET / STATUS_CLEAR: | ||||
|  * | ||||
|  * Indicates which GPIOs have triggered an interrupt.  Interrupt status should | ||||
|  * be reset by writing to STATUS or STATUS_CLEAR. | ||||
|  * | ||||
|  * (_SET/_CLEAR function similarly to OUT registers) | ||||
|  */ | ||||
| 
 | ||||
| struct GPIO_REGS { | ||||
|     uint32_t volatile OUT;              // 0x00
 | ||||
|     uint32_t volatile OUT_SET;          // 0x04
 | ||||
|     uint32_t volatile OUT_CLEAR;        // 0x08
 | ||||
|     uint32_t volatile ENABLE_OUT;       // 0x0c
 | ||||
|     uint32_t volatile ENABLE_OUT_SET;   // 0x10
 | ||||
|     uint32_t volatile ENABLE_OUT_CLEAR; // 0x14
 | ||||
|     uint32_t volatile IN;               // 0x18
 | ||||
|     uint32_t volatile STATUS;           // 0x1c
 | ||||
|     uint32_t volatile STATUS_SET;       // 0x20
 | ||||
|     uint32_t volatile STATUS_CLEAR;     // 0x24
 | ||||
|     uint32_t volatile CONF[16];         // 0x28 - 0x64
 | ||||
|     uint32_t volatile PWM;              // 0x68
 | ||||
|     uint32_t volatile RTC_CALIB;        // 0x6c
 | ||||
|     uint32_t volatile RTC_CALIB_RESULT; // 0x70
 | ||||
| } __attribute__ (( packed )); | ||||
| 
 | ||||
| /* Double-check the structure size to make sure the compiler hasn't done
 | ||||
|  * something strange (or somebody typoed in the struct definition, etc) | ||||
|  */ | ||||
| _Static_assert(sizeof(struct GPIO_REGS) == 0x74, "GPIO_REGS is the wrong size"); | ||||
| 
 | ||||
| /* Bit mapping for CONF[i] registers */ | ||||
| 
 | ||||
| /* GPIO.CONF[i] control the pin behavior for the corresponding GPIO in/output.
 | ||||
|  * | ||||
|  * GPIO_CONF_CONFIG (multi-value) | ||||
|  *     FIXME: Unclear what these do.  Need to find a better name. | ||||
|  * | ||||
|  * GPIO_CONF_WAKEUP_ENABLE (boolean) | ||||
|  *     Can an interrupt contion on this pin wake the processor from a sleep | ||||
|  *     state? | ||||
|  * | ||||
|  * GPIO_CONF_INTTYPE (multi-value) | ||||
|  *     Under what conditions this GPIO input should generate an interrupt. | ||||
|  *     (see gpio_inttype_t enum below for values) | ||||
|  * | ||||
|  * GPIO_CONF_DRIVER_ENABLE (boolean) | ||||
|  *     When set, a high output state will pull the pin up to +Vcc (3.3V).  When | ||||
|  *     cleared, output functions in "open drain" mode (low state will pull down | ||||
|  *     to ground, but high state allows output to "float"). | ||||
|  * | ||||
|  * GPIO_CONF_SOURCE_PWM (boolean) | ||||
|  *     When set, GPIO pin output will be connected to the sigma-delta PWM | ||||
|  *     generator (controlled by the GPIO.PWM register).  When cleared, pin | ||||
|  *     output will function as a normal GPIO output (controlled by the | ||||
|  *     GPIO.OUT* registers). | ||||
|  */ | ||||
| 
 | ||||
| #define GPIO_CONF_CONFIG_M       0x00000003 | ||||
| #define GPIO_CONF_CONFIG_S       11 | ||||
| #define GPIO_CONF_WAKEUP_ENABLE  BIT(10) | ||||
| #define GPIO_CONF_INTTYPE_M     0x00000007 | ||||
| #define GPIO_CONF_INTTYPE_S     7 | ||||
| #define GPIO_CONF_DRIVER_ENABLE  BIT(2) | ||||
| #define GPIO_CONF_SOURCE_PWM     BIT(0) | ||||
| 
 | ||||
| /* Valid values for the GPIO_CONF_INTTYPE field */ | ||||
| typedef enum { | ||||
|     GPIO_INTTYPE_NONE       = 0, | ||||
|     GPIO_INTTYPE_EDGE_POS   = 1, | ||||
|     GPIO_INTTYPE_EDGE_NEG   = 2, | ||||
|     GPIO_INTTYPE_EDGE_ANY   = 3, | ||||
|     GPIO_INTTYPE_LEVEL_LOW  = 4, | ||||
|     GPIO_INTTYPE_LEVEL_HIGH = 5, | ||||
| } gpio_inttype_t; | ||||
| 
 | ||||
| /* Bit mapping for PWM register */ | ||||
| 
 | ||||
| #define GPIO_PWM_ENABLE          BIT(16) | ||||
| #define GPIO_PWM_PRESCALER_M     0x000000ff | ||||
| #define GPIO_PWM_PRESCALER_S     8 | ||||
| #define GPIO_PWM_TARGET_M        0x000000ff | ||||
| #define GPIO_PWM_TARGET_S        0 | ||||
| 
 | ||||
| /* Bit mapping for RTC_CALIB register */ | ||||
| 
 | ||||
| #define GPIO_RTC_CALIB_START     BIT(31) | ||||
| #define GPIO_RTC_CALIB_PERIOD_M  0x000003ff | ||||
| #define GPIO_RTC_CALIB_PERIOD_S  0 | ||||
| 
 | ||||
| /* Bit mapping for RTC_CALIB_RESULT register */ | ||||
| 
 | ||||
| #define GPIO_RTC_CALIB_RESULT_READY       BIT(31) | ||||
| #define GPIO_RTC_CALIB_RESULT_READY_REAL  BIT(30) | ||||
| #define GPIO_RTC_CALIB_RESULT_VALUE_M     0x000fffff | ||||
| #define GPIO_RTC_CALIB_RESULT_VALUE_S     0 | ||||
| 
 | ||||
| #endif /* _ESP_GPIO_REGS_H */ | ||||
|  | @ -17,6 +17,7 @@ | |||
| #include "esp/types.h" | ||||
| 
 | ||||
| #include "esp/iomux_regs.h" | ||||
| #include "esp/gpio_regs.h" | ||||
| 
 | ||||
| /* Internal macro, only defined in header body */ | ||||
| #define _REG(BASE, OFFSET) (*(esp_reg_t)((BASE)+(OFFSET))) | ||||
|  | @ -31,7 +32,7 @@ | |||
| #define UART0_BASE (MMIO_BASE + 0) | ||||
| #define SPI1_BASE  (MMIO_BASE + 0x0100) | ||||
| #define SPI_BASE   (MMIO_BASE + 0x0200) | ||||
| #define GPIO0_BASE (MMIO_BASE + 0x0300) | ||||
| //#define GPIO0_BASE (MMIO_BASE + 0x0300)
 | ||||
| #define TIMER_BASE (MMIO_BASE + 0x0600) | ||||
| #define RTC_BASE   (MMIO_BASE + 0x0700) | ||||
| //#define IOMUX_BASE (MMIO_BASE + 0x0800)
 | ||||
|  | @ -42,79 +43,6 @@ | |||
| #define RTCS_BASE  (MMIO_BASE + 0x1100) | ||||
| #define RTCU_BASE  (MMIO_BASE + 0x1200) | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|  * Based on descriptions by mamalala at https://github.com/esp8266/esp8266-wiki/wiki/gpio-registers
 | ||||
|  */ | ||||
| 
 | ||||
| /** GPIO OUTPUT registers GPIO_OUT_REG, GPIO_OUT_SET, GPIO_OUT_CLEAR
 | ||||
|  * | ||||
|  * Registers for pin outputs. | ||||
|  * | ||||
|  * _SET and _CLEAR write-only registers set and clear bits in _REG, | ||||
|  * respectively. | ||||
|  * | ||||
|  * ie | ||||
|  * GPIO_OUT_REG |= BIT(3); | ||||
|  * and | ||||
|  * GPIO_OUT_SET = BIT(3); | ||||
|  * | ||||
|  * ... are equivalent, but latter uses less CPU cycles. | ||||
|  */ | ||||
| #define GPIO_OUT_REG   _REG(GPIO0_BASE, 0x00) | ||||
| #define GPIO_OUT_SET   _REG(GPIO0_BASE, 0x04) | ||||
| #define GPIO_OUT_CLEAR _REG(GPIO0_BASE, 0x08) | ||||
| 
 | ||||
| /* GPIO DIR registers GPIO_DIR_REG, GPIO_DIR_SET, GPIO_DIR_CLEAR
 | ||||
|  * | ||||
|  * Set bit in DIR register for output pins. Writing to _SET and _CLEAR | ||||
|  * registers set and clear bits in _REG, respectively. | ||||
| */ | ||||
| #define GPIO_DIR_REG   _REG(GPIO0_BASE, 0x0C) | ||||
| #define GPIO_DIR_SET   _REG(GPIO0_BASE, 0x10) | ||||
| #define GPIO_DIR_CLEAR _REG(GPIO0_BASE, 0x14) | ||||
| 
 | ||||
| 
 | ||||
| /* GPIO IN register GPIO_IN_REG
 | ||||
|  * | ||||
|  * Reads current input values. | ||||
|  */ | ||||
| #define GPIO_IN_REG    _REG(GPIO0_BASE, 0x18) | ||||
| 
 | ||||
| /* GPIO interrupt 'status' flag
 | ||||
| 
 | ||||
|    Bit set if interrupt has fired (see below for interrupt config | ||||
|    registers. | ||||
| 
 | ||||
|    Lower 16 bits only are used. | ||||
| */ | ||||
| #define GPIO_STATUS_REG   _REG(GPIO0_BASE,0x1c) | ||||
| #define GPIO_STATUS_SET   _REG(GPIO0_BASE,0x20) | ||||
| #define GPIO_STATUS_CLEAR _REG(GPIO0_BASE,0x24) | ||||
| 
 | ||||
| #define GPIO_STATUS_MASK  0x0000FFFFL | ||||
| 
 | ||||
| /* GPIO pin control registers for GPIOs 0-15
 | ||||
|  * | ||||
|  */ | ||||
| #define GPIO_CTRL_REG(GPNUM) _REG(GPIO0_BASE, 0x28+(GPNUM*4)) | ||||
| 
 | ||||
| #define GPIO_SOURCE_GPIO 0 | ||||
| #define GPIO_SOURCE_DAC BIT(0) /* "Sigma-Delta" */ | ||||
| #define GPIO_SOURCE_MASK BIT(0 | ||||
| 
 | ||||
| #define GPIO_DRIVE_PUSH_PULL 0 | ||||
| #define GPIO_DRIVE_OPEN_DRAIN BIT(2) | ||||
| #define GPIO_DRIVE_MASK BIT(2) | ||||
| 
 | ||||
| #define GPIO_INT_NONE 0 | ||||
| #define GPIO_INT_RISING BIT(7) | ||||
| #define GPIO_INT_FALLING BIT(8) | ||||
| #define GPIO_INT_CHANGE (BIT(7)|BIT(8)) | ||||
| #define GPIO_INT_LOW BIT(9) | ||||
| #define GPIO_INT_HIGH (BIT(7)|BIT(9)) | ||||
| #define GPIO_INT_MASK (BIT(7)|BIT(8)|BIT(9)) | ||||
| 
 | ||||
| /* TIMER registers
 | ||||
|  * | ||||
|  * ESP8266 has two hardware(?) timer counters, FRC1 and FRC2. | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue