|
2 | 2 |
|
3 | 3 | #define LED_PINCOUNT (23) |
4 | 4 |
|
5 | | -volatile int drive_strength; |
| 5 | +static uint32_t g_pindrive_strong; |
6 | 6 |
|
7 | 7 | typedef enum { |
8 | 8 | FLOATING, |
9 | 9 | LOW, |
10 | 10 | HIGH, |
11 | 11 | } tristate_t; |
12 | 12 |
|
13 | | -typedef struct { |
14 | | - uint32_t *port_buf; |
15 | | - uint32_t *cfg_buf; |
16 | | - uint32_t pin; |
17 | | -} pinctrl_t; |
| 13 | +typedef struct pinbank { |
| 14 | + volatile uint8_t *base; |
18 | 15 |
|
19 | | -static void gpio_buf_set(pinctrl_t pinctl, tristate_t state) |
| 16 | + uint32_t bankpins_mask; |
| 17 | + |
| 18 | + uint32_t out_val; |
| 19 | + uint32_t dir_val; |
| 20 | + uint32_t drv_val; |
| 21 | +} pinbank_t; |
| 22 | + |
| 23 | +typedef struct pindesc { |
| 24 | + pinbank_t *bank; |
| 25 | + uint32_t pin_mask; |
| 26 | +} pindesc_t; |
| 27 | + |
| 28 | +static struct pinbanks { |
| 29 | + pinbank_t A; |
| 30 | + pinbank_t B; |
| 31 | +} g_PinBanks; |
| 32 | + |
| 33 | + |
| 34 | +static void gpio_pin_set(const pindesc_t *desc, tristate_t state) |
20 | 35 | { |
21 | | - if (state == FLOATING) { |
22 | | - *(pinctl.cfg_buf) &= ~pinctl.pin; |
23 | | - } else { |
24 | | - if (state == HIGH) |
25 | | - *(pinctl.port_buf) |= pinctl.pin; |
26 | | - else |
27 | | - *(pinctl.port_buf) &= ~pinctl.pin; |
28 | | - |
29 | | - *(pinctl.cfg_buf) |= pinctl.pin; |
| 36 | + switch(state) { |
| 37 | + case FLOATING: |
| 38 | + desc->bank->dir_val &= ~desc->pin_mask; |
| 39 | + break; |
| 40 | + case HIGH: |
| 41 | + desc->bank->dir_val |= desc->pin_mask; |
| 42 | + desc->bank->out_val |= desc->pin_mask; |
| 43 | + break; |
| 44 | + default: |
| 45 | + desc->bank->dir_val |= desc->pin_mask; |
| 46 | + desc->bank->out_val &= ~desc->pin_mask; |
30 | 47 | } |
31 | 48 | } |
32 | 49 |
|
33 | | -void led_setDriveStrength(int is_20mA) |
| 50 | +static void gpio_bank_tristate(pinbank_t *bank) |
34 | 51 | { |
35 | | - drive_strength = is_20mA; |
| 52 | + volatile uint32_t *out = (volatile uint32_t *)(bank->base + GPIO_OUT); |
| 53 | + volatile uint32_t *drv = (volatile uint32_t *)(bank->base + GPIO_PD_DRV); |
| 54 | + volatile uint32_t *dir = (volatile uint32_t *)(bank->base + GPIO_DIR); |
| 55 | + uint32_t bankpins_mask; |
| 56 | + |
| 57 | + // Get state for pins we do NOT control |
| 58 | + bankpins_mask = bank->bankpins_mask; |
| 59 | + bank->out_val = |
| 60 | + (bank->out_val & bankpins_mask) | (*out & ~bankpins_mask); |
| 61 | + bank->dir_val = |
| 62 | + (bank->dir_val & bankpins_mask) | (*dir & ~bankpins_mask); |
| 63 | + bank->drv_val = |
| 64 | + (g_pindrive_strong & bank->dir_val & bankpins_mask) | (*drv & ~bankpins_mask); |
| 65 | + |
| 66 | + // ... and tristate pins, we DO control |
| 67 | + *dir = (bank->dir_val & ~bankpins_mask); |
36 | 68 | } |
37 | 69 |
|
38 | | -static void gpio_buf_apply( |
39 | | - volatile uint8_t *gpio_base, |
40 | | - uint32_t *port, uint32_t *cfg, |
41 | | - uint32_t *mask) |
| 70 | +static void gpio_bank_apply(pinbank_t *bank) |
42 | 71 | { |
43 | | - if (drive_strength) { |
44 | | - uint32_t *drv = (uint32_t *)(gpio_base + GPIO_PD_DRV); |
45 | | - *drv = (*drv & ~*mask) | (*cfg & *mask); |
46 | | - } |
47 | | - uint32_t *dir = (uint32_t *)(gpio_base + GPIO_DIR); |
48 | | - *dir = (*dir & ~*mask) | (*cfg & *mask); |
| 72 | + volatile uint32_t *out = (volatile uint32_t *)(bank->base + GPIO_OUT); |
| 73 | + volatile uint32_t *drv = (volatile uint32_t *)(bank->base + GPIO_PD_DRV); |
| 74 | + volatile uint32_t *dir = (volatile uint32_t *)(bank->base + GPIO_DIR); |
49 | 75 |
|
50 | | - uint32_t *out = (uint32_t *)(gpio_base + GPIO_OUT); |
51 | | - *out = (*out & ~*mask) | (*port & *mask); |
| 76 | + *out = bank->out_val; |
| 77 | + *drv = bank->drv_val; |
| 78 | + *dir = bank->dir_val; |
52 | 79 | } |
53 | 80 |
|
54 | | -static uint32_t PA_buf; |
55 | | -static uint32_t PB_buf; |
56 | | -static uint32_t PAcfg_buf; |
57 | | -static uint32_t PBcfg_buf; |
58 | | -static uint32_t PA_mask; |
59 | | -static uint32_t PB_mask; |
60 | | - |
61 | | -#define GPIO_APPLY_ALL() \ |
62 | | - gpio_buf_apply(BA_PA, &PA_buf, &PAcfg_buf, &PA_mask); \ |
63 | | - gpio_buf_apply(BA_PB, &PB_buf, &PBcfg_buf, &PB_mask) |
64 | | - |
65 | | -#define PINCTRL(x, pin) { \ |
66 | | - &P##x##_buf, \ |
67 | | - &P##x##cfg_buf, \ |
68 | | - GPIO_Pin_##pin \ |
| 81 | +#define GPIO_APPLY_ALL() do { \ |
| 82 | + gpio_bank_tristate(&g_PinBanks.A); \ |
| 83 | + gpio_bank_tristate(&g_PinBanks.B); \ |
| 84 | + gpio_bank_apply(&g_PinBanks.A); \ |
| 85 | + gpio_bank_apply(&g_PinBanks.B); \ |
| 86 | +} while (0) |
| 87 | + |
| 88 | + |
| 89 | +#define PINDESC(bank_, pinnr_) { \ |
| 90 | + &g_PinBanks.bank_ , \ |
| 91 | + GPIO_Pin_##pinnr_ \ |
69 | 92 | } |
70 | 93 |
|
71 | | -static const pinctrl_t led_pins[LED_PINCOUNT] = { |
72 | | - PINCTRL(A, 15), // A |
73 | | - PINCTRL(B, 18), // B |
74 | | - PINCTRL(B, 0), // C |
75 | | - PINCTRL(B, 7), // D |
76 | | - PINCTRL(A, 12), // E |
77 | | - PINCTRL(A, 10), // F |
78 | | - PINCTRL(A, 11), // G |
79 | | - PINCTRL(B, 9), // H |
80 | | - PINCTRL(B, 8), // I |
81 | | - PINCTRL(B, 15), // J |
82 | | - PINCTRL(B, 14), // K |
83 | | - PINCTRL(B, 13), // L |
84 | | - PINCTRL(B, 12), // M |
85 | | - PINCTRL(B, 5), // N |
86 | | - PINCTRL(A, 4), // O |
87 | | - PINCTRL(B, 3), // P |
88 | | - PINCTRL(B, 4), // Q |
89 | | - PINCTRL(B, 2), // R |
90 | | - PINCTRL(B, 1), // S |
| 94 | +static const pindesc_t led_pins[LED_PINCOUNT] = { |
| 95 | + PINDESC(A, 15), // A |
| 96 | + PINDESC(B, 18), // B |
| 97 | + PINDESC(B, 0), // C |
| 98 | + PINDESC(B, 7), // D |
| 99 | + PINDESC(A, 12), // E |
| 100 | + PINDESC(A, 10), // F |
| 101 | + PINDESC(A, 11), // G |
| 102 | + PINDESC(B, 9), // H |
| 103 | + PINDESC(B, 8), // I |
| 104 | + PINDESC(B, 15), // J |
| 105 | + PINDESC(B, 14), // K |
| 106 | + PINDESC(B, 13), // L |
| 107 | + PINDESC(B, 12), // M |
| 108 | + PINDESC(B, 5), // N |
| 109 | + PINDESC(A, 4), // O |
| 110 | + PINDESC(B, 3), // P |
| 111 | + PINDESC(B, 4), // Q |
| 112 | + PINDESC(B, 2), // R |
| 113 | + PINDESC(B, 1), // S |
91 | 114 | #ifdef USBC_VERSION |
92 | | - PINCTRL(B, 6), // T |
| 115 | + PINDESC(B, 6), // T |
93 | 116 | #else |
94 | | - PINCTRL(B, 23), // T |
| 117 | + PINDESC(B, 23), // T |
95 | 118 | #endif |
96 | | - PINCTRL(B, 21), // U |
97 | | - PINCTRL(B, 20), // V |
98 | | - PINCTRL(B, 19), // W |
| 119 | + PINDESC(B, 21), // U |
| 120 | + PINDESC(B, 20), // V |
| 121 | + PINDESC(B, 19), // W |
99 | 122 | }; |
100 | 123 |
|
101 | 124 | void led_init() |
102 | 125 | { |
103 | | - for (int i=0; i<LED_PINCOUNT; i++) { |
104 | | - if (led_pins[i].port_buf == &PA_buf) |
105 | | - PA_mask |= led_pins[i].pin; |
106 | | - else |
107 | | - PB_mask |= led_pins[i].pin; |
| 126 | + int i; |
| 127 | + |
| 128 | + g_PinBanks.A.base = BA_PA; |
| 129 | + g_PinBanks.B.base = BA_PB; |
| 130 | + for (i = 0; i < LED_PINCOUNT; i++) { |
| 131 | + led_pins[i].bank->bankpins_mask |= led_pins[i].pin_mask; |
108 | 132 | } |
109 | 133 | } |
110 | 134 |
|
111 | 135 | void leds_releaseall() { |
112 | 136 | for (int i=0; i<LED_PINCOUNT; i++) |
113 | | - gpio_buf_set(led_pins[i], FLOATING); |
| 137 | + gpio_pin_set(led_pins + i, FLOATING); |
| 138 | + g_pindrive_strong = 0x00000000; |
114 | 139 | GPIO_APPLY_ALL(); |
115 | 140 | } |
116 | 141 |
|
117 | 142 | static void led_write2dcol_raw(int dcol, uint32_t val) |
118 | 143 | { |
119 | | - // TODO: assert params |
120 | | - gpio_buf_set(led_pins[dcol], HIGH); |
| 144 | + int on_count; |
| 145 | + int pin_value; |
| 146 | + |
| 147 | + gpio_pin_set(led_pins + dcol, HIGH); |
| 148 | + on_count = 0; |
121 | 149 | for (int i=0; i<LED_PINCOUNT; i++) { |
122 | 150 | if (i == dcol) continue; |
123 | | - gpio_buf_set(led_pins[i], (val & 0x01) ? LOW : FLOATING); // danger: floating=0 (led off) or low=1 (led on) |
| 151 | + pin_value = FLOATING; |
| 152 | + if (val & 0x01) { |
| 153 | + on_count++; |
| 154 | + pin_value = LOW; // pin LOW => LED on |
| 155 | + } |
| 156 | + gpio_pin_set(led_pins + i, pin_value); |
124 | 157 | val >>= 1; |
125 | 158 | } |
| 159 | + g_pindrive_strong = 0x00000000; |
| 160 | + if (on_count > 5) |
| 161 | + g_pindrive_strong = 0xFFFFFFFF; |
126 | 162 | GPIO_APPLY_ALL(); |
127 | 163 | } |
128 | 164 |
|
129 | | -static uint32_t combine_cols(uint16_t col1_val, uint16_t col2_val) |
| 165 | +static uint32_t combine_cols(uint16_t col1_val, uint16_t col2_val) |
130 | 166 | { |
131 | 167 | uint32_t dval = 0; |
132 | 168 | dval |= ((col1_val & 0x01) << (LED_ROWS*2)); |
@@ -156,13 +192,24 @@ void led_write2dcol(int dcol, uint16_t col1_val, uint16_t col2_val) |
156 | 192 |
|
157 | 193 | void led_write2row_raw(int row, int which_half, uint32_t val) |
158 | 194 | { |
159 | | - row = row*2 + (which_half != 0); |
| 195 | + int on_count; |
| 196 | + int pin_value; |
160 | 197 |
|
161 | | - gpio_buf_set(led_pins[row], LOW); |
| 198 | + row = row*2 + (which_half != 0); |
| 199 | + gpio_pin_set(led_pins + row, LOW); |
| 200 | + on_count = 0; |
162 | 201 | for (int i=0; i<LED_PINCOUNT; i++) { |
163 | 202 | if (i == row) continue; |
164 | | - gpio_buf_set(led_pins[i], (val & 0x01) ? HIGH : FLOATING); |
| 203 | + pin_value = FLOATING; |
| 204 | + if (val & 0x01) { |
| 205 | + on_count++; |
| 206 | + pin_value = HIGH; |
| 207 | + } |
| 208 | + gpio_pin_set(led_pins + i, pin_value); |
165 | 209 | val >>= 1; |
166 | 210 | } |
| 211 | + g_pindrive_strong = 0x00000000; |
| 212 | + if (on_count > 5) |
| 213 | + g_pindrive_strong = 0xFFFFFFFF; |
167 | 214 | GPIO_APPLY_ALL(); |
168 | 215 | } |
0 commit comments