I have two simple LED flasher programs the flash at 1 sec intervals for my BluePills.One method uses HAL_GPIO_TogglePin to toggle the LED state and the other uses Set and Reset to toggle the LED state. The Set and Reset functions as expected but the HAL_GPIO_TogglePin definitely is working but it has a almost PWM effect part of the time. I have tried both methods on 2 different Bluepills with same results for both.
while (1)
{
if (__HAL_TIM_GET_COUNTER(&htim1) >= 32000)
{
HAL_GPIO_TogglePin(User_LED_GPIO_Port, User_LED_Pin);
}
and
while (1)
{
if (__HAL_TIM_GET_COUNTER(&htim1) >= 32000)
{
HAL_GPIO_WritePin(User_LED_GPIO_Port, User_LED_Pin, GPIO_PIN_SET);
}
else {
HAL_GPIO_WritePin(User_LED_GPIO_Port, User_LED_Pin, GPIO_PIN_RESET);
}
Thanks Codo, you were 100% right. I modified it to
if ((__HAL_TIM_GET_COUNTER(&htim1) == 32000) || (__HAL_TIM_GET_COUNTER(&htim1)==0))
{
HAL_GPIO_TogglePin(User_LED_GPIO_Port, User_LED_Pin);
timer_val = __HAL_TIM_GET_COUNTER(&htim1);
}
Funny thing is I originally followed the Digikey example and it did the same thing.
while (1)
{
// If enough time has passed (1 second), toggle LED and get new timestamp
if (__HAL_TIM_GET_COUNTER(&htim16) - timer_val >= 10000)
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
timer_val = __HAL_TIM_GET_COUNTER(&htim16);
}
oh well, for what i want, the Set Reset works better anyways. Thanks
Related
Issue
I have an input signal that shall trigger an interrupt. The ISR then shall toggle an output pin 24 times.
Having it set up stright forward I am facing the issue that the ISR is executed twice.
System
IDE: STM32CubeIDE v1.10.0
uC: STM32L4A6 (NUCLEO-L4A6ZG)
Pin config:
PC12 (DATA_READY_NEG_EDGE) = External interrupt, falling edge (externally pulled down with 100k and 100n)
PC11 (ADC_SPI_CLK) = Output
Code
The auto code generator pulls out the following code
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
/* EXTI line interrupt detected */
if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != 0x00u)
{
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
HAL_GPIO_EXTI_Callback(GPIO_Pin);
}
}
The callback function looks like this (but I don't think that this is part of the issue):
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == DATA_READY_NEG_EDGE_Pin) // INT Source is pin PC12
{
HAL_GPIO_TogglePin(LED_RED_GPIO_Port, LED_RED_Pin); // Toggle LED
for (int var = 0; var < 24; ++var)
{
HAL_GPIO_TogglePin(ADC_SPI_CLK_GPIO_Port, ADC_SPI_CLK_Pin);
HAL_GPIO_TogglePin(ADC_SPI_CLK_GPIO_Port, ADC_SPI_CLK_Pin);
}
}
}
This way the interrupt is falsely triggered twice.
Interchange the sequence of "CLEAR" and "Callback" function call in the IRQHandler, the ISR is correctly only called once. But this is a hack and every time I generate the code it is reverted again, so for sure not a solution.
What issue do I have and what could be the workaround?
Thx for any support!
I am very new to stm32, I have STM32F411RE Nucleo and I work in STM32CubeIDE. First I need to turn on the LED with the first click on the push button, and the LED stays on until the next click. On the second click, the LED starts blinking with a frequency of 10 Hz, then I need a third click, a fourth, and so on. I have written the code for the first one and it works but I don't know how to make the LED do something with every click on the push button. I don't know how to write the program so it recognizes when a button is pressed for the second, third, or fourth time...
So far I have this:
// read the status of the GPIO button pin
button_val = HAL_GPIO_ReadPin(GPIOC, B1_Pin);
// check if it is high or low
if(button_val == PRESSED) // the button is pressed
{
// if pressed - turn led on
HAL_GPIO_WritePin(LD2_GPIO_Port,LD2_Pin, SET);
// if not pressed - turn led off
// HAL_GPIO_WritePin(LD2_GPIO_Port,LD2_Pin, RESET);
}
When I run this the LED lights up when I press the button. Then I have this code for the second press on the button but it doesn't work.
if(button_val == SECONDPRESSED)
{
// turn led on
HAL_GPIO_WritePin(LD2_GPIO_Port,LD2_Pin, SET);
HAL_Delay(1000);
// turn led off
HAL_GPIO_WritePin(LD2_GPIO_Port,LD2_Pin, RESET);
HAL_Delay(1000);
}
This is a general programming question and not really a STM32-specific issue, since the necessary STM32 hardware input/output seems to work already in your case.
In the STM32F4xx HAL driver code it can be seen that HAL_GPIO_ReadPin() returns a value of type GPIO_PinState, which can be in two states, GPIO_PIN_SET or GPIO_PIN_RESET, GPIO pins are either in HIGH or LOW state.
Now, to make the program cycle through different program states becomes a matter of software programming, there are no hardware specific functions involved. To realize the desired behavior, a very basic state machine could be used for example, using the following states:
typedef enum {
PROG_STATE_INIT = 0,
PROG_STATE_FIRST_PRESS,
PROG_STATE_SECOND_PRESS,
PROG_STATE_THIRD_PRESS,
PROG_STATE_FOURTH_PRESS,
_PROG_STATE_COUNT
} prog_state;
Then, in the main loop, the program could cycle through the states for example like this:
static prog_state _prog_state = PROG_STATE_INIT;
static GPIO_PinState _pin_state_prev = GPIO_PIN_RESET;
const GPIO_PinState pin_state = HAL_GPIO_ReadPin(GPIOC, B1_Pin);
if (pin_state == GPIO_PIN_SET && pin_state != _pin_state_prev) {
++_prog_state; /* next state */
if (_prog_state >= _PROG_STATE_COUNT) {
_prog_state = PROG_STATE_FIRST_PRESS;
}
}
_pin_state_prev = pin_state;
switch (_prog_state) {
case PROG_STATE_INIT:
/* do nothing here, LED is already off */
break;
case PROG_STATE_FIRST_PRESS:
/* turn LED on and let it stay on */
HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET);
break;
case PROG_STATE_SECOND_PRESS:
HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
HAL_Delay(50); /* ~10 Hz blinky */
break;
case PROG_STATE_THIRD_PRESS:
/* TODO */
break;
case PROG_STATE_FOURTH_PRESS:
/* TODO */
break;
case _PROG_STATE_COUNT:
default:
/* unexpected */
break;
}
Like already mentioned in the comments above, software/hardware button debouncing might be needed. But for this exercise, it can also be OK to simply add a short delay to the main loop, so that fast GPIO state changes have no effect.
And to expand on the exercise, GPIO EXTI interrupts could be used to react to GPIO state changes. And it might be interesting to set up a timer/counter to let the LED blink precisely at 10 Hz, and control it via the state machine.
I am looking a code to get the latch switch function using STM32.
The below code which I have tried is working in stm32 but only a push button function without latch.
while (1)
{
if(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_13)== GPIO_PIN_RESET )
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);
}
else
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET);
}
}
Can some one help me to make the GPIOA,GPIO_PIN_5 pin high always on the first press of the button and the GPIOA,GPIO_PIN_5 low always at the second press ?
The function will be similar as in the below video https://www.youtube.com/watch?v=zzWzSPdxA0U
Thank you all in advance.
There are several problems with the code. There is no memory function and you are reading the button at max speed.
This is fixed by sleeping for a period of time to allow for human reaction speed and button noise. You also need a variable to store the previous state.
while (1)
{
if(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_13)== GPIO_PIN_RESET )
{
static bool state = false;
if(state == false)
{
state = true;
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);
}
else
{
state = false
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET);
}
while(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_13)== GPIO_PIN_RESET){} // wait for button to be released, otherwise it will keep toggling every 500ms
}
delay_ms(500);
}
This is C++ code as it uses bool. int with the values 1 and 0 can be used for C.
What is done is a variable state is declared and kept in heap memory because of the static keyword. (Instead of stack memory which would be destroyed when the scope of the outer if statement is exited) It is initialized to false and then updated when you press the button.
Possible (crude) solution:
#include <stdbool.h>
#define BUTTON_DOWN() (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_RESET)
#define LED(on) HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, (on) ? GPIO_PIN_SET : GPIO_PIN_RESET)
static bool _pressed_before = false;
static bool _led = false;
/* somewhere in main loop */
{
const bool pressed = BUTTON_DOWN();
if (pressed && !_pressed_before) { /* button pressed? */
_led = !_led; /* toggle LED state */
LED(_led);
}
_pressed_before = pressed; /* remember state */
}
Some notes:
Instead of constantly polling the state, you could use an external GPIO interrupt (search for GPIO EXTI). And it is almost always necessary to use hardware debouncing on the button pin (RC filter) and/or use software debouncing to prevent falsely detected edges. - Also: This question is not really STM32 / hardware specific, so you could find more general answers by searching the webs more broadly on these topics.
I am facing a strange behavior i am working on project using ATMEL MCU (ATMEGA328p) with huge amount with strings so i stored it in flash memory and during run time i read it from flash memory and send it via UART.
i don't know if this the problem or not because i was using the same technique before in other projects but what is different here the amount of strings larger than before.
void PLL_void_UART_SendSrting_F(U8_t* RXBuffer,const char * str , U8_t UART_No)
{
unsigned int _indx=0;
memset(RXBuffer,'\0', A9G_RX_Index); // Initialize the string
RXBuffer[A9G_RX_Index-1]='\0';
// cli();
while((RXBuffer[_indx]=pgm_read_byte(&(*str))))
{
str++;
_indx++;
_delay_ms(5);
}
// sei();
PLL_void_UART_SendSrting(RXBuffer,0);
}
But after awhile the whole program stuck and even after doing hard reset , to work again i should unplug and plug the power again.
Notes :-
- I am sure that hard reset working
- I am using timers in background as system tick .
The code is unsafe; you do nothing to prevent a buffer overrun.
Consider the safer, and simpler:
void PLL_void_UART_SendString_F( U8_t* RXBuffer, const char* str, U8_t UART_No )
{
unsigned index = 0 ;
RXBuffer[A9G_RX_Index - 1] = '\0' ;
while( index < A9G_RX_Index - 1 &&
0 != (RXBuffer[index] = pgm_read_byte( &str[index] )) )
{
index++ ;
}
PLL_void_UART_SendSrting( RXBuffer, 0 ) ;
}
Even then you have to be certain RXBuffer is appropriately sized and str is nul terminated.
Thank you for support
I found the issues, it was because watch dog timer keep the MCU in restart mode even when i press the hardware rest. this is because, i was considering all registers,flags back to its default value after rest.WDT Block Digram
i was doing that in code when MCU start execution the code like that :
U8_t PLL_U8_System_Init()
{
static U8_t SetFalg=0;
PLL_void_TimerInit(); // General Timer Initialize
PLL_WDT_Init(); // Initialize WDT and clear WDRF
wdt_enable(WDTO_8S); // Enable WDT Each 2 S
........
}
but once WDT occurred and rest the program then CPU found WDRF flag is set so it keep in rest for ever since i did power rest.
Solution
i have to clear WDT timer once program start first, before execute any code and its work
U8_t PLL_U8_System_Init()
{
static U8_t SetFalg=0;
PLL_void_TimerInit(); // General Timer Initialize
PLL_WDT_Init(); // Initialize WDT and clear WDRF
wdt_enable(WDTO_8S); // Enable WDT Each 2 S
........
}
this is what written in data sheet
Note: If the Watchdog is accidentally enabled, for example by a runaway pointer or
brown-out condition, the device will be reset and the Watchdog Timer will stay enabled. If
the code is not set up to handle the Watchdog, this might lead to an eternal loop of timeout resets. To avoid this situation, the application software should always clear the
Watchdog System Reset Flag (WDRF) and the WDE control bit in the initialization
routine, even if the Watchdog is not in use.
Im struggling with ssd1289# stm32f411v some time . I have problem with refreshing data on screen . Changes on variable like temperature from bmp180 etc seems to be not refreshes . Strings on screen are putted one on another without clearing background. I wrote function cleaning whole screen but its to slow and screen starts blinking :
void LCD_Clear(void) {
uint32_t i = 0;
LCD_SetWindow(0,0,320,240);
LCD_write_command(0x0022);
for (i = 0; i < 320*240; i++) { LCD_write_data(0x0000); }
}
I try use timers interrupts with 65Hz refreshing and lower freq ::
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
if ( htim ->Instance == TIM3 ){
LCD_Clear();
LCD_PutStr(10,30,temperature,RGB565(255,192,255));
LCD_PutStr(60,30,pressure,RGB565(255,192,255));
}
}
and on debugging i have error :
Info : The target is not running when halt was requested, stopping GDB.
When i remove LCD_Clear(); from timfunction i have symptoms as described on beginning.
Any ideas what is wrong .
AS PeterJ_01 says : execution time is much too long .
In interruption i dont clear whole screen only partial :)