Skip to content

Commit 24d82d1

Browse files
committed
[STM32F1] Fix pull overwrite
This fix addresses issue #2638 for STM32F1. The STM32F1 family has a diffeerent register set for pull-up and pull-down settings. The same principle to read HW state is applied, as in commit: [STM32] Fix pull over write to all families except registers are different. Also in this patch we make code a bit more linear. Depending on pin_index, different register and shift index must be used. Instead of checking this in several place, let's make a check at the beginning of the function and use local register and shift variables.
1 parent af51027 commit 24d82d1

File tree

2 files changed

+59
-23
lines changed

2 files changed

+59
-23
lines changed

targets/TARGET_STM/TARGET_STM32F1/gpio_irq_api.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ static void gpio_irq6(void)
163163
}
164164

165165
extern uint32_t Set_GPIO_Clock(uint32_t port_idx);
166+
extern void pin_function_gpiomode(PinName pin, uint32_t gpiomode);
166167

167168
int gpio_irq_init(gpio_irq_t *obj, PinName pin, gpio_irq_handler handler, uint32_t id)
168169
{
@@ -267,15 +268,14 @@ void gpio_irq_free(gpio_irq_t *obj)
267268
gpio_channel->channel_gpio[gpio_idx] = 0;
268269
gpio_channel->channel_pin[gpio_idx] = 0;
269270

270-
// Disable EXTI line
271-
pin_function(obj->pin, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0));
271+
// Disable EXTI line, but don't change pull-up config
272+
pin_function_gpiomode(obj->pin, STM_MODE_INPUT);
272273
obj->event = EDGE_NONE;
273274
}
274275

275276
void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable)
276277
{
277278
uint32_t mode = STM_MODE_IT_EVT_RESET;
278-
uint32_t pull = GPIO_NOPULL;
279279

280280
if (enable) {
281281
if (event == IRQ_RISE) {
@@ -317,7 +317,7 @@ void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable)
317317
}
318318
}
319319

320-
pin_function(obj->pin, STM_PIN_DATA(mode, pull, 0));
320+
pin_function_gpiomode(obj->pin, mode);
321321
}
322322

323323
void gpio_irq_enable(gpio_irq_t *obj)

targets/TARGET_STM/TARGET_STM32F1/pinmap.c

Lines changed: 55 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -162,10 +162,19 @@ void pin_mode(PinName pin, PinMode mode)
162162

163163
uint32_t port_index = STM_PORT(pin);
164164
uint32_t pin_index = STM_PIN(pin);
165-
166165
// Enable GPIO clock
167166
uint32_t gpio_add = Set_GPIO_Clock(port_index);
168167
GPIO_TypeDef *gpio = (GPIO_TypeDef *)gpio_add;
168+
__IO uint32_t* gpio_reg_hl;//gpio register depends on bit index (high or low)
169+
uint32_t shift;
170+
171+
if (pin_index < 8) {
172+
shift = (pin_index * 4);
173+
gpio_reg_hl = &(gpio->CRL);
174+
} else {
175+
shift = (pin_index % 8) * 4;
176+
gpio_reg_hl = &(gpio->CRH);
177+
}
169178

170179
// Configure open-drain and pull-up/down
171180
switch (mode) {
@@ -174,16 +183,9 @@ void pin_mode(PinName pin, PinMode mode)
174183
case PullUp:
175184
case PullDown:
176185
// Set pull-up / pull-down for Input mode
177-
if (pin_index < 8) {
178-
if ((gpio->CRL & (0x03 << (pin_index * 4))) == 0) { // MODE bits = Input mode
179-
gpio->CRL |= (0x08 << (pin_index * 4)); // Set pull-up / pull-down
180-
gpio->CRL &= ~(0x04 << (pin_index * 4)); // ENSURES GPIOx_CRL.CNFx.bit0 = 0
181-
}
182-
} else {
183-
if ((gpio->CRH & (0x03 << ((pin_index % 8) * 4))) == 0) { // MODE bits = Input mode
184-
gpio->CRH |= (0x08 << ((pin_index % 8) * 4)); // Set pull-up / pull-down
185-
gpio->CRH &= ~(0x04 << ((pin_index % 8) * 4)); // ENSURES GPIOx_CRH.CNFx.bit0 = 0
186-
}
186+
if ((*gpio_reg_hl & (0x03 << shift)) == 0) { // MODE bits = Input mode
187+
*gpio_reg_hl |= (0x08 << shift); // Set pull-up / pull-down
188+
*gpio_reg_hl &= ~(0x04 << shift); // ENSURES GPIOx_CRL.CNFx.bit0 = 0
187189
}
188190
// Now it's time to setup properly if pullup or pulldown. This is done in ODR register:
189191
// set pull-up => bit=1, set pull-down => bit = 0
@@ -195,17 +197,51 @@ void pin_mode(PinName pin, PinMode mode)
195197
break;
196198
case OpenDrain:
197199
// Set open-drain for Output mode (General Purpose or Alternate Function)
198-
if (pin_index < 8) {
199-
if ((gpio->CRL & (0x03 << (pin_index * 4))) > 0) { // MODE bits = Output mode
200-
gpio->CRL |= (0x04 << (pin_index * 4)); // Set open-drain
201-
}
202-
} else {
203-
if ((gpio->CRH & (0x03 << ((pin_index % 8) * 4))) > 0) { // MODE bits = Output mode
204-
gpio->CRH |= (0x04 << ((pin_index % 8) * 4)); // Set open-drain
205-
}
200+
if ((*gpio_reg_hl & (0x03 << shift)) > 0) { // MODE bits = Output mode
201+
*gpio_reg_hl |= (0x04 << shift); // Set open-drain
206202
}
207203
break;
208204
default:
209205
break;
210206
}
211207
}
208+
209+
/* Internal function for setting the gpiomode/function
210+
* without changing Pull mode
211+
*/
212+
void pin_function_gpiomode(PinName pin, uint32_t gpiomode) {
213+
214+
/* Read current pull state from HW to avoid over-write*/
215+
uint32_t port_index = STM_PORT(pin);
216+
uint32_t pin_index = STM_PIN(pin);
217+
GPIO_TypeDef *gpio = (GPIO_TypeDef *) Set_GPIO_Clock(port_index);
218+
uint32_t pull = PullNone;
219+
__IO uint32_t* gpio_reg_hl;//gpio register depends on bit index (high or low)
220+
uint32_t shift;
221+
222+
if (pin_index < 8) {
223+
shift = (pin_index * 4);
224+
gpio_reg_hl = &(gpio->CRL);
225+
} else {
226+
shift = (pin_index % 8) * 4;
227+
gpio_reg_hl = &(gpio->CRH);
228+
}
229+
230+
/* Check if pull/pull down is active */
231+
if ((!(*gpio_reg_hl & (0x03 << shift))) // input
232+
&& (!!(*gpio_reg_hl & (0x08 << shift))) // pull-up / down
233+
&& (!(*gpio_reg_hl & (0x04 << shift)))) { // GPIOx_CRL.CNFx.bit0 = 0
234+
if (!!(gpio->ODR & (0x01 << pin_index))) {
235+
pull = PullUp;
236+
} else {
237+
pull = PullDown;
238+
}
239+
} else { //output
240+
if (!!(*gpio_reg_hl & (0x04 << shift))) { //open drain
241+
pull = OpenDrain;
242+
}
243+
}
244+
245+
/* Then re-use global function for updating the mode part*/
246+
pin_function(pin, STM_PIN_DATA(gpiomode, pull, 0));
247+
}

0 commit comments

Comments
 (0)