STM32 HAL_GPIO_WritePin not working, SCK weirdness - Page 1
Forum section: electronics / general

author: davegravy
author_rank: Regular Contributor
timestamp: January 23, 2022, 03:55:20 pm
content: I'm fairly new to MCU development so there's probably something basic wrong here.I'm having trouble achieving basic GPIO output control in two different but possibly related situations. Working on a NUCLEO board (STM32U5).Problem #1:I was successfully able to control GPIO output level of ADC_SEL0_Pin at one point recently but suddenly HAL_GPIO_WritePin is seemingly having no effect (measuring with a multimeter). Changing the pin's level in STM32CubeIDE does still have an effect - I think generates the below code inMX_GPIO_Init():Code:/*Configure GPIO pin Output Level */HAL_GPIO_WritePin(GPIOA, ADC_SEL1_Pin|ADC_SEL0_Pin, GPIO_PIN_SET);For some reason trying to modify the pin's level in main() after the call toMX_GPIO_Init()no longer seems to do anything.I've attached my main.c. Note that the code shows both calls setting to the pin HIGH, but if I change the second call to LOW the pin will measure as HIGH - only the first call has any effect. What might cause this?Problem #2:I am responding to an interrupt raised by the Data Ready Line (DRL) signal output by the external ADC I am reading from (SPI configured as read-only master mode). In the ISR I callHAL_SPI_Receive()to read 32 bits. Inspecting the SCK line it rests at digital HIGH following the read, then halfway to the next DRL pulse it drops to LOW, but it seems to bounce a lot on the way (see attached logic analyzer output).I need the SCK line to remain quiet between reads so to combat this I tried to manually force SCK low immediately following the read (PA5 is the SPI1_SCK pin):Code:/* USER CODE BEGIN 4 */void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin) {if (GPIO_Pin == SPI1_DRL_Trigger_Pin){HAL_SPI_Receive(&hspi1,(uint8_t *)spi_buf, 1, 100);HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET);}}/* USER CODE END 4 */Sadly this seems to have no impact. Why does the SCK line change state when it does, why does it bounce, and why doesn't my code prevent it? What should I do to keep the line quiet?

author: DavidAlfa
author_rank: Super Contributor
timestamp: January 23, 2022, 04:20:48 pm
content: Attach also main.h (it's where GPIOs are defined) and the .ioc file.What's GPIO_PIN_5? SCK? Writing to a GPIO being used by a peripheral will have no effect.Your problem comes from read-only master mode. That mode will send pulses non-stop. When you stop it, it will still send some extra bytes.Try half-duplex master instead receiving-only master. Reading will still work, but the control is different, it has to write to SPI DR register to send the clocks.It's slower but maintains full control of the clock line.Another issue: Is DRL triggering every 40us? That's pretty fast for an interrupt, the stm32 might not have enough time. The SPI peripheral might be going crazy.Seems a job for the DMA!If the interrupts overlap, your code will never be executed. The interrupt will exit and inmediately enter again.That would explain few things.Zoom in the SCK waveform to see better what's going on.

author: Siwastaja
author_rank: Super Contributor
timestamp: January 23, 2022, 04:31:28 pm
content: How convoluted can a simple GPIO toggle be.Try something like this:Code:void main(){RCC->AHB2ENR1 |= 1UL; // GPIOA clock enableGPIOA->MODER = 1UL<<(2 * pin_number_goes_here); // make it outputwhile(1){GPIOA->BSRR = 1UL<<(pin number goes here); // turn it on, or...GPIOA->BSRR = 1UL<<(16 + pin number goes here); // turn it off}}Assuming Cube can create working linker script and startup code, nothing else is needed, this is the full main.c.Disclaimer: no idea if STM32U5 requires some extra tricks. Probably not.But worry not, some are even worse. In nRF52 series, example that should print "hello world", compiles over 30 C files with around 100 000 lines of code, produces a 200Kbyte binary, and fails to print "hello world".The solution is not to care about this shit, but write code like any sensible human being would do if such crap didn't exist in the first place. Look for 15-20 year old AVR/PIC examples for reference. Then the reference manual.

author: DavidAlfa
author_rank: Super Contributor
timestamp: January 23, 2022, 04:39:43 pm
content: Siwastaja, HAL_GPIO_WritePin does exactly that. I guess that's a interrupt issue, or something he forgot to tell.Code:void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState){if (PinState != GPIO_PIN_RESET){GPIOx->BSRR = GPIO_Pin;}else{GPIOx->BSRR = (uint32_t)GPIO_Pin << 16u;}}

author: alexanderbrevig
author_rank: Frequent Contributor
timestamp: January 23, 2022, 04:45:18 pm
content: You probably do not want to start a blocking SPI call in an ISR.

author: Siwastaja
author_rank: Super Contributor
timestamp: January 23, 2022, 04:48:23 pm
content: Quote from: DavidAlfa on January 23, 2022, 04:39:43 pmThus, the solution is, as always, minimize towards minimum example reproducing just the issue and nothing else. In case of IO pin not working, just the IO pin thing. The funny thing is, while doing that, you usually find the problem yourself!

author: DavidAlfa
author_rank: Super Contributor
timestamp: January 23, 2022, 04:51:25 pm
content: Alexander, I think it's fine, it's just a 32-bit SPI read. For larger transfers, probably a DMA is the way to go.You're the master, nothing can cause the communication to stall.

author: alexanderbrevig
author_rank: Frequent Contributor
timestamp: January 23, 2022, 06:06:35 pm
content: Sure, it's fine now but who knows down the line when specs chnage. ISRs should be kept as short as possible. I state it as a fact, because I think it is.QuoteThose lines operate on different pins. That may explain it

author: SiliconWizard
author_rank: Super Contributor
timestamp: January 23, 2022, 06:22:04 pm
content: Yep, I suspect GPIOA / GPIO_PIN_5 is either not the proper pin, or it had not been configured - in which case, HAL_GPIO_WritePin() would have effectively no effect.As to SCK, there seems to be some ringing. I'd suspect you didn't properly connect the ground connection of your logic analyzer to the board's ground.

author: davegravy
author_rank: Regular Contributor
timestamp: January 23, 2022, 06:32:27 pm
content: Quote from: DavidAlfa on January 23, 2022, 04:20:48 pmFocusing on the SPI issue for now since I'm able to set ADC_SEL0_Pin and ADC_SEL1_Pin in the Init section successfully at least, and I don't really need to change it post-init for the testing I'm doing. I'll explore it more later.I tried Half Duplex Master mode, and unfortunately no change in the SCK behavior. Attached some LA output zoomed in on the read where SCK does what it's supposed to (except for being left high) and then another screen grab of the weird ringing behavior mid-way between DRL pulses.Also attaching the other files you mentioned. ​I appreciate DMA is probably the way to go ultimately but I was hoping for a quick and easy (for a beginner) way to validate the ADC operation as a stepping stone. I gather to use DMA I'd have to trigger a timer with DRL and then use that to trigger DMA which may not be so beginner-friendly. If you think I'm wasting my time with the interrupt approach though that's valuable to know.

author: davegravy
author_rank: Regular Contributor
timestamp: January 23, 2022, 06:39:35 pm
content: Quote from: SiliconWizard on January 23, 2022, 06:22:04 pmPA5 is configured in the IDE as SPI1_SCK. Am I to understand it can't be manually controlled as a GPIO when it's part of an SPI interface?Hmm, the ground on the LA for SCK certainly looks connected (to the same physical ground pin on the NUCLEO that all the other channels are using). I swapped the SDO and SCK channels on the LA and the ringing followed SCK.

author: SiliconWizard
author_rank: Super Contributor
timestamp: January 23, 2022, 06:42:06 pm
content: Quote from: davegravy on January 23, 2022, 06:39:35 pmYou figured that right. Pins can be configured either as GPIO or as an alternate function (such as a peripheral's signal) - mutually exclusive.Quote from: davegravy on January 23, 2022, 06:39:35 pmHaving an oscilloscope would help here. But it's still likely this is a probing issue.

author: davegravy
author_rank: Regular Contributor
timestamp: January 23, 2022, 08:18:48 pm
content: Quote from: SiliconWizard on January 23, 2022, 06:42:06 pmSCK scope attached (X10 probe). My scope is old and bandwidth limited but I think it's fine to show what's happening here. Looks like SCK isn'tt being driven LOW, just allowed to slowly discharge.That's why I was trying to force it LOW using GPIO.

author: wek
author_rank: Frequent Contributor
timestamp: January 24, 2022, 07:39:55 am
content: If you use Cube/HAL, it disables SPI after transfer has finished. Read Cube's sources, they are open. That means, SPI pins (including SCK and including NSS if driven from SPI) go threestate. They are still under SPI control, as long as the respective GPIOx_MODER is set to AF.The solution is simple: don't use Cube/HAL, write your own code. Cube/HAL - as any "library" - inevitably caters only for a miniscule subset of what the hardware allows, i.e. for the "usual cases".Or use Cube/HAL and try to invent some kludge. Pulldown (internal or external) on given pin may or may not help, depending on what do you want to achieve and what are the parasitics on that pin. You can also switch the pin to GPIO Output in GPIOx_MODER after SPI has finished.JW