1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
|
#include "gpio.h"
#include "ch573/pfic.h"
#include "isr_vector.h"
/* Sets all the GPIO pins to INPUT_PULL_UP configuration. This is to reduce
* electrical noise in the system. */
void gpio_init()
{
// Set GPIO's to input.
GPIO_PORT.dir_reg.set(GPIO_PORT_A, 0x0);
GPIO_PORT.dir_reg.set(GPIO_PORT_B, 0x0);
// Turn off all the pull-down resistors.
GPIO_PORT.pd_drv_reg.set(GPIO_PORT_A, 0x0);
GPIO_PORT.pd_drv_reg.set(GPIO_PORT_B, 0x0);
// Turn on the pull up resistors.
GPIO_PORT.pu_reg.set(GPIO_PORT_A, 0xffffffff);
GPIO_PORT.pu_reg.set(GPIO_PORT_B, 0xffffffff);
}
void gpio_configure_pin(gpio_pin_t pin, gpio_config_t cfg)
{
int ipin = pin;
struct ch573_gpio__gpio_port_t* port;
if (pin & IS_PORT_B) {
port = GPIO_PORT_B;
ipin &= ~IS_PORT_B;
} else {
port = GPIO_PORT_A;
}
switch (cfg) {
case PIN_CFG_INPUT_FLOATING:
GPIO_PORT.dir.set(port, DIR_IN, ipin);
GPIO_PORT.pu.set(port, DISABLED, ipin);
GPIO_PORT.pd_drv.set(port, 0, ipin);
break;
case PIN_CFG_INPUT_PULL_UP:
GPIO_PORT.dir.set(port, DIR_IN, ipin);
GPIO_PORT.pu.set(port, ENABLED, ipin);
GPIO_PORT.pd_drv.set(port, 0, ipin);
break;
case PIN_CFG_INPUT_PULL_DOWN:
GPIO_PORT.dir.set(port, DIR_IN, ipin);
GPIO_PORT.pu.set(port, DISABLED, ipin);
GPIO_PORT.pd_drv.set(port, 1, ipin);
break;
case PIN_CFG_OUTPUT_5mA:
GPIO_PORT.dir.set(port, DIR_OUT, ipin);
GPIO_PORT.pu.set(port, DISABLED, ipin);
GPIO_PORT.pd_drv.set(port, 0, ipin);
break;
case PIN_CFG_OUTPUT_20mA:
GPIO_PORT.dir.set(port, DIR_OUT, ipin);
GPIO_PORT.pu.set(port, DISABLED, ipin);
GPIO_PORT.pd_drv.set(port, 1, ipin);
break;
}
}
int gpio_read(gpio_pin_t pin)
{
int ipin = pin;
struct ch573_gpio__gpio_port_t* port;
if (pin & IS_PORT_B) {
port = GPIO_PORT_B;
ipin &= ~IS_PORT_B;
} else {
port = GPIO_PORT_A;
}
return !!GPIO_PORT.pin.in.get(port, ipin);
}
void gpio_set(gpio_pin_t pin, int high)
{
int ipin = pin;
struct ch573_gpio__gpio_port_t* port;
if (pin & IS_PORT_B) {
port = GPIO_PORT_B;
ipin &= ~IS_PORT_B;
} else {
port = GPIO_PORT_A;
}
GPIO_PORT.out.set(port, !!high, ipin);
}
void gpio_enable_alternate_function(alternate_function_t afn, int enable)
{
if (enable) {
GPIO_I.pin_alternate.set(GPIO, 1 << afn);
} else {
GPIO->pin_alternate &= ~(1 << afn);
};
}
#define PFIC ch573_pfic__pfic
static void enable_gpio_pfic(int irq)
{
PFIC->interrupt_priority_threshold = 0x10;
PFIC->interrupt_enable |= irq;
}
void gpio_enable_interrupt(gpio_pin_t pin, interrupt_mode_t int_mode)
{
int ipin = pin;
struct ch573_gpio__gpio_port_t* port;
volatile uint16_t* port_int_mode;
volatile uint16_t* port_int_enable;
volatile uint16_t* port_int_flag;
if (pin & IS_PORT_B) {
port = GPIO_PORT_B;
ipin &= ~IS_PORT_B;
port_int_mode = &GPIO->pb_interrupt_mode;
port_int_flag = &GPIO->pb_interrupt_flag;
port_int_enable = &GPIO->pb_interrupt_enable;
enable_gpio_pfic(IRQ_GpioB);
} else {
port = GPIO_PORT_A;
port_int_mode = &GPIO->pa_interrupt_mode;
port_int_flag = &GPIO->pa_interrupt_flag;
port_int_enable = &GPIO->pa_interrupt_enable;
enable_gpio_pfic(IRQ_GpioA);
}
switch (int_mode) {
case INT_MODE_FALLING_EDGE:
*port_int_mode |= 1 << ipin;
GPIO_PORT.clr.set(port, 1 << ipin);
break;
case INT_MODE_RISING_EDGE:
*port_int_mode |= 1 << ipin;
GPIO_PORT.out.set(port, 1, ipin);
break;
case INT_MODE_LEVEL_HIGH:
*port_int_mode &= ~(1 << ipin);
GPIO_PORT.out.set(port, 1, ipin);
break;
case INT_MODE_LEVEL_LOW:
*port_int_mode &= ~(1 << ipin);
GPIO_PORT.clr.set(port, 1 << ipin);
break;
}
*port_int_flag = 1 << ipin;
*port_int_enable |= 1 << ipin;
}
extern gpio_callback_t GPIO_LISTENERS_START;
extern gpio_callback_t GPIO_LISTENERS_END;
void fire_irq(volatile uint16_t* int_flag_ptr, int is_port_b)
{
gpio_callback_t* cur = &GPIO_LISTENERS_START;
uint16_t pin = 0;
uint16_t intflag = *int_flag_ptr;
for (pin = 0; pin < 16; ++pin) {
if (intflag & (1 << pin)) {
// If this pin triggered an interrupt, fire the GPIO listeners.
for (cur = &GPIO_LISTENERS_START; cur < &GPIO_LISTENERS_END; ++cur) {
(*cur)(pin | is_port_b);
}
*int_flag_ptr |= 1 << pin; // Clear the interrupt for this pin.
}
}
*int_flag_ptr = 0xffff;
}
IRQ(gpio_b)
{
fire_irq(&GPIO->pb_interrupt_flag, IS_PORT_B);
}
IRQ(gpio_a)
{
fire_irq(&GPIO->pa_interrupt_flag, 0);
}
|