-
Re: Setting GPIO BSRRH register doesn't seem to work
ilg Feb 7, 2019 7:46 AM (in response to brendansimon)most probably a bug in the GPIO emulation.
the code is:
https://github.com/gnu-mcu-eclipse/qemu/blob/gnuarmeclipse-dev/hw/cortexm/stm32/gpio.c
after lots of definitions, at the end you can see the actual functionality. please feel free to suggest improvements.
-
Re: Setting GPIO BSRRH register doesn't seem to work
brendansimon Feb 7, 2019 6:07 PM (in response to ilg)Without knowing the code base or wanting to take the plunge to learn how to build qemu etc, the following might be a fix ?
static void stm32f4_gpio_bsrr_post_write_callback(Object *reg, Object *periph, uint32_t addr, uint32_t offset, unsigned size, peripheral_register_t value, peripheral_register_t full_value) { STM32GPIOState *state = STM32_GPIO_STATE(periph); Object *odr = state->reg.odr; assert(odr); // 'value' may be have any size, use full_word. uint32_t bits_to_set = (full_value & 0x0000FFFF); uint32_t bits_to_reset = ((full_value >> 16) & 0x0000FFFF); // Clear the BR bits and set the BS bits. uint32_t new_value = (peripheral_register_get_raw_value(odr) & (~bits_to_reset)) | bits_to_set; stm32_gpio_update_odr_and_idr(state, odr, state->reg.idr, new_value); #if 1 //FIXME:BJS: clear BR and BS bits in the BSRR register after ODR is set peripheral_register_write_value( state-reg.>bsrr, 0 ); #endif }
Guess you would have to do a similar thing for all the families (F0, F1, etc).
Might be possible to consolidate that in one place and clear the `brr` register as well, to cover all families ?
static void stm32_gpio_update_odr_and_idr(STM32GPIOState *state, Object *odr, Object *idr, uint16_t new_value) { assert(odr); // Preserve old value, to compute changed bits uint16_t old_value = peripheral_register_get_raw_value(odr); // Update register value. Per documentation, the upper 16 bits // always read as 0, so write is used, to apply the mask. peripheral_register_write_value(odr, new_value); #if 1 //FIXME:BJS: clear BSRR and BRR registers after ODR is set peripheral_register_write_value( state->reg.bsrr, 0 ); peripheral_register_write_value( state->reg.brr, 0 ); #endif stm32_gpio_set_odr_irqs(state, old_value, new_value); stm32_gpio_update_idr(state, idr, new_value); }
Brendan.
-
Re: Setting GPIO BSRRH register doesn't seem to work
ilg Feb 7, 2019 5:41 PM (in response to brendansimon)I'll take a look after the toolchain release is out.
-
Re: Setting GPIO BSRRH register doesn't seem to work
brendansimon Feb 7, 2019 6:00 PM (in response to brendansimon)This assumes that `peripheral_register_write_value()` just updates the internal representation of a register, and doesn't actually trigger any action.
The intent is to just clear the internal register state, so that a subsequent write to the BSRR register (BSRRL, BSRRH) doesn't have any carry over effects.
-
Re: Setting GPIO BSRRH register doesn't seem to work
ilg Feb 8, 2019 5:13 PM (in response to brendansimon)there must be something that I'm missing, since my code to blink the led uses both the low and the high halves of the register, and obviously works.
void BlinkLed::turnOn () { if (fIsActiveLow) { BLINK_GPIOx(fPortNumber)->BSRR = BLINK_PIN_MASK(fBitNumber + 16); } else { BLINK_GPIOx(fPortNumber)->BSRR = fBitMask; } } void BlinkLed::turnOff () { if (fIsActiveLow) { BLINK_GPIOx(fPortNumber)->BSRR = fBitMask; } else { BLINK_GPIOx(fPortNumber)->BSRR = BLINK_PIN_MASK(fBitNumber + 16); } }
can you be more specific where do you think the problem is?
and possibly share the code that works on the board and fails on QEMU?
-
Re: Setting GPIO BSRRH register doesn't seem to work
brendansimon Feb 8, 2019 10:27 PM (in response to ilg)Here's snippet of the relevant code to set a pin high or low. I think the main difference is use of BSSRH and BSSRL individually (16-bit), rather than setting them together with BSSR (32-bit).
void pin_set_low( U8_t pin ) { pin_info[pin].gpio->BSRRH = (1 << pin_info[pin].bit_pos); } void pin_set_high( U8_t pin ) { pin_info[pin].gpio->BSRRL = (1 << pin_info[pin].bit_pos); }
What I observe is that the pin is set high ok, but wont set low (after it's been set high).
My guess it's to do with this part of the QEMU GPIO code, where `full_value` is remembering the previous set high operation in BSRRL (the low 16-bits of BSRR) and overrides the new bit being set in BSRRH to set the pin low, due to the order of
new_value = odr_value & (~bits_to_reset) | bits_to_set;
full function below
static void stm32f4_gpio_bsrr_post_write_callback(Object *reg, Object *periph, uint32_t addr, uint32_t offset, unsigned size, peripheral_register_t value, peripheral_register_t full_value) { STM32GPIOState *state = STM32_GPIO_STATE(periph); Object *odr = state->reg.odr; assert(odr); // 'value' may be have any size, use full_word. uint32_t bits_to_set = (full_value & 0x0000FFFF); uint32_t bits_to_reset = ((full_value >> 16) & 0x0000FFFF); // Clear the BR bits and set the BS bits. uint32_t new_value = (peripheral_register_get_raw_value(odr) & (~bits_to_reset)) | bits_to_set; stm32_gpio_update_odr_and_idr(state, odr, state->reg.idr, new_value); #if 1 //FIXME:BJS: clear BR and BS bits in the BSRR register after ODR is set peripheral_register_write_value( state->reg.bsrr, 0 ); #endif }
-
Re: Setting GPIO BSRRH register doesn't seem to work
ilg Feb 8, 2019 10:47 PM (in response to brendansimon)> I think the main difference is use of BSSRH and BSSRL individually (16-bit), rather than setting them together with BSSR (32-bit)
I see. probably this is why my code works, because when using 32-bit the problem is hidden.
I had some setbacks with the toolchain, it'll probably take 1-2 more days. everything seems fine now, except the problem of windows paths with spaces, which is partly identified, but not yet solved.
-
Re: Setting GPIO BSRRH register doesn't seem to work
brendansimon Feb 8, 2019 11:16 PM (in response to brendansimon)I've cloned the GME QEMU repo and had a quick look through the code.
I think `peripheral_register_write_value()` would work ok. It only sets the state value of a register object.
An alternative is to use `peripheral_register_set_raw_value()` which does the exact same thing, but without masking out non-writable bits. It's a little more efficient and probably ok to use for this use case (i.e. clearing BSRR register after the bits have been finished with).
-
Re: Setting GPIO BSRRH register doesn't seem to work
ilg Feb 8, 2019 11:22 PM (in response to brendansimon)ok, thank you.
you're only a small step away from being able to build it, install an ubunu 18 lts vm, add docker (https://gnu-mcu-eclipse.github.io/developer/build-binaries-prerequisites-xbb/ ), and you'll be able to build qemu yourself (https://github.com/gnu-mcu-eclipse/qemu-build ).
-
Re: Setting GPIO BSRRH register doesn't seem to work
ilg Feb 8, 2019 11:30 PM (in response to ilg)could you also open a ticket at https://github.com/gnu-mcu-eclipse/qemu/issues ?
-
Re: Setting GPIO BSRRH register doesn't seem to work
brendansimon Feb 10, 2019 4:15 AM (in response to ilg)
-
-
-
-
-
-
-
-
-
Re: Setting GPIO BSRRH register doesn't seem to work
brendansimon Feb 11, 2019 6:04 AM (in response to brendansimon)I confirm that QEMU 2.8.0-4 resolves the issue.
Thanks, Liviu !!
I have a function that sets a pin state to high or low, and code that calls that function to set the red LED on the STM32F4 Discovery board to high and low (it pulses).
The code works on a real Disco board, but in QEMU the LED turns on but never turns off.
To set the pin high (LED on), the appropriate bit is set in the GPIO BSSRL register. This works the the LED turns on
To set the pin low (LED off), the same bit is set in the GPIO BSSRH register. This doesn't work. The LED remains on in QEMU.
I've confirmed that using GPIO ODR in conjunction with |= bit and &= ~bit works ok, but that's not what I want to do.
I can get it to work (i.e. the LED to toggle) by doing BSSRL = bit, and BSSRH &= ~bit and vice-versa (but that is definitely wrong for all the other bits).
So I suspect there is a bug in QEMU which is looking at both registers and if the BSSRL is set, it ignores the BSSRH. Just a guess. I imagine the code should look at ODR and just set or clear the bits in there when emulating the register access.
Any thoughts?
Thanks, Brendan.