STM32F103 | libopencm3 | GPIO toggle using interrupt issue - stm32

So, I am trying to toggle a LED based on an interrupt from a button.
Ideally the when the button is pressed the LED should toggle i.e. switch on if its off and vice versa. But when I execute this code it toggles and returns to its original state.
Expected Result:
LED OFF » Button pressed » LED ON
Practical Result:
LED OFF » Button pressed » LED ON » LED OFF
I have added a delay for debouncing so bouncing is out of the picture. Also the GPIO's ODR is set in the ISR when the button is pressed so how is it getting cleared while exiting the ISR?
I would really appreciate your help! Thank you.
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/exti.h>
#include <libopencm3/cm3/nvic.h>
#define LEDPIN (GPIO13)
static void exti_setup(void)
{
/* Enable GPIOA and AFIO clock. */
rcc_periph_clock_enable(RCC_GPIOB);
rcc_periph_clock_enable(RCC_AFIO);
/* Enable EXTI0 interrupt. */
nvic_enable_irq(NVIC_EXTI15_10_IRQ);
/* Set GPIO12 (in GPIO port B) to input */
gpio_set_mode(GPIOB, GPIO_MODE_INPUT,GPIO_CNF_INPUT_FLOAT, GPIO12);
/* Configure the EXTI subsystem. */
exti_select_source(EXTI12,GPIOB);
exti_set_trigger(EXTI12, EXTI_TRIGGER_BOTH);
exti_enable_request(EXTI12);
}
static void gpio_setup(void)
{
/* Enable clock for GPIO port C */
rcc_periph_clock_enable(RCC_GPIOC);
/* Set LEDPIN (in GPIO port C) as opendrain output */
gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, LEDPIN);
}
void delay(){
int i;
for (i = 0; i < 1000000; i++)
{
__asm__("nop");
}
}
void handler(){
delay();
gpio_toggle(GPIOC, GPIO13);
}
int main(void)
{
gpio_setup();
exti_setup();
while (1) {
__asm__("nop");
}
return 0;
}
void exti15_10_isr()
{
exti_reset_request(EXTI12);
handler();
}

Not open drain but push-pull
Butttons should not use EXTI as it makes debouncing more complicated, often floods the uC with interrupts, Use timer interrupt instead to read the key and debounce.

As #dev_eng rightly pointed out the issue was the interrupt being configured as both RISING/FALLING edge.
Configuring it with single EDGE that is either RISING or FALLING solved my problem.

Related

The sample code does not work on STM32F103C6

experts.
I am new to STM32.
So I downloaded some sample code from github.
https://github.com/yohanes-erwin/stm32f103-keil
And I download the simple led blinking code of it to the STM32F103C6 developing board but it doesn't work at all.
The original program embedded on the chip had been erased successfully ( originally the led was always on and LCD screen shows some text, but now after I download the code, the led is off and screen off. So I think the downloading is successful.) but the code does not work.
When I download the original code to the chip, it works again. So I think the chip isn't broken.
I think it's because of compatibility of sample code and my chip. The sample code was written for STM32F103C8. But it was a very simple code. What is the reason?
Here is the code.
#include "stm32f10x.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"
void delay(unsigned int nCount);
GPIO_InitTypeDef GPIO_InitStruct;
int main (void)
{
// Enable clock for GPIOA
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// Configure PA4 as push-pull output
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStruct);
while (1)
{
/* Toggle LED on PA0 */
// Reset bit will turn on LED (because the logic is interved)
GPIO_ResetBits(GPIOA, GPIO_Pin_4);
delay(1000);
// Set bit will turn off LED (because the logic is interved)
GPIO_SetBits(GPIOA, GPIO_Pin_4);
delay(1000);
}
}
// Delay function
void delay(unsigned int nCount)
{
unsigned int i, j;
for (i = 0; i < nCount; i++)
for (j = 0; j < 0x2AFF; j++);
}

libopencm3 STM32G0: GPIO inputs don't work

My code does not set the GPIOs as inputs on my Nucleo-G071RB. The MODER register ist completly set (0xffffffff) and the GPIOs work as outputs.
What did I wrong?
Code:
#include <libopencm3/stm32/gpio.h>
void setupGpio(void);
void setupGpio(void) {
// set input
gpio_mode_setup(GPIOB, GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN, GPIO_ALL);
}
int main(void){
setupGpio();
while (1)
{
// Loop with pin read
}
}
You need to enable peripheral clock first. Not only GPIO but almost all peripherals need this.
Modify your function as below:
void setupGpio(void) {
rcc_periph_clock_enable(RCC_GPIOB); // Enable GPIOB clock
gpio_mode_setup(GPIOB, GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN, GPIO_ALL);
}

Does HAL_NVIC_SetPendingIRQ call the ISR to execute?

I am really new to STM32 world so I came across this while reading:
void HAL_NVIC_SetPendingIRQ(IRQn_Type IRQn);
This will cause the interrupt to fire, as it would be generated by the hardware. A distinctive feature
of Cortex-M processors it that it is possible to programmatically fire an interrupt inside the ISR
routine of another interrupt.
I got this from the book Mastering STM32 (by Carmine Noviello page 208). From this I have understood that If we set this pending bit even from the main function, then the interrupt is generated.
So to try this out, I have written this code:
while (1)
{
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_SET);
for(int i = 0; i <10000000; i++);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET);
for(int i = 0; i <10000000; i++);
HAL_NVIC_SetPendingIRQ(EXTI0_IRQn);
}
}
along with this call back function
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_PIN){
HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_15);
}
I have programmed GPIO_PIN_0 as source of interrupt and when I press the push button connected to PA0 the Interrupt works perfectly i.e. ISR is executed. To my surprice HAL_NVIC_SetPendingIRQ function doesn't generate interrupt. I don't understand why?
More Info:
I am using STM32F411VET6 DISCO board
I am using STM32CubeIDE to program the board
Thank you #Tagli. I have found the function HAL_GPIO_EXTI_IRQHandler inside stm32f4xx_hal_gpio.c file. Defalult definition was like this:
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
/* EXTI line interrupt detected */
if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET)
{
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
HAL_GPIO_EXTI_Callback(GPIO_Pin);
}
}
I got why the GPIO was not being toggled. It was the same reason you have commented above.
I have modified to prove it.
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
/* EXTI line interrupt detected */
HAL_GPIO_EXTI_Callback(GPIO_Pin);
if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET)
{
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
HAL_GPIO_EXTI_Callback(GPIO_Pin);
}
}
Now the callback function is called when the HAL_NVIC_SetPendingIRQ(EXTI0_IRQn); is being called

How to implement UART1 Interrupts correctly on STM32f103xx while running a main programme?

I am trying to program my bluePill to blink an LED at the PB11 pin while echoing whats being send over the serial port UART1.
as far as my knowledge, Interrupts allows us to run the programme we want and while running it if any flag triggered an interrupt signal the program the control will be diverted to run the interrupt service routine while the original program is running, am I correct here?
So, I'm trying to keep the Green LED blinking and when I type anything on the serial port the red LED blinks while the green is blinking and the blue led must be always turned on unless data is being sent.
Problem 1:
The green led never blinks!
Problem 2:
Whenever sending letters or numbers through Arduino serial monitor the received echo is always 2 letters out of the entire send letters, also the echo is always on the same line, I mean not not on a newline
so typing Hello and pressing enter yields He and when typing hi there and pressing enter the it just adds the first two letters like so Hehi , why?
my code is
/* ********************** Project Description ***********************
STM32f103xx BluePill Board
PB10 = Green LED
PB11 = Blue LED (To be toggled)
PB0 = Red LED (PWM OUTPUT Controlling the Brightness)
PB9 = Push Button for toggling the state of the blue LED
PA0 = Potentiomater Pin (Analog Input)
USART1 Activated and Sends the Voltage of PA0 to the user1
*/
#include "stm32f1xx.h" // Include the MCU header
#include <stdbool.h> // Boolean Library header
#include <stdint.h>
// Prototypes:
void UART1_Init(void); //Enable UART1 on PA9(Tx) & PA10(Rx).
void portsEnable(void); //Enable Clock for desired MCU Ports.
void delay(uint32_t delay); //Intuduce Delays.
void pinsConfig(void); //Configure the used pins.
// Defines and Macros
int main(void)
{
// Inintialization:
portsEnable();
pinsConfig();
UART1_Init(); // Enable USART1 & interrupts # 8Mhz clock Speed only # 9600Bps
while(1)
{
// ******** Blink The green LED ***********************
GPIOB->BSRR = GPIO_BSRR_BS11;
delay(100000);
GPIOB->BSRR = GPIO_BSRR_BR11;
delay(100000);
} // End of while loop
} // End main() loop
// ************** Function Implimentation *****************************
void UART1_Init(void) // Initiallize USART1
{
// Reset Setting (8bit, one stop bit, no parity)
// Enable clock for UART1 First after already enabling the PortA clock
RCC->APB2ENR |= RCC_APB2ENR_USART1EN; // Enable Clock to the USART1 Module
// Pin Configuration for the USART1 Peripheral where Tx(PA9) = AF Push-Pull and Rx = Input Floating
// Setting Tx (PA9) Pin
GPIOA->CRH |= ((1<<4) | (1<<5)); // Set PA9 to Output 50Mhz Mode
GPIOA->CRH &= ~(1<<6); // Configure it to be an AF push-pull
GPIOA->CRH |= (1<<7); // Same as above^
// Setting Rx (PA10) pin
// Nothing to be set as the reset value makes it an input pin with floating configuration
// Set the Baud-Rate
USART1->BRR = 0x341; //# 8Mhz, USARTDIV = 8Mhz/(16*9600) = 52.083 -> 52=0x34 and 0.083 * 16 = 1.328 = 1 which is 0x1
// Enable Interrupts for the USART1 Module:
// A peripheral can generates a flag at a certain event, this flag can trigger an interrupt signal but first the certain event interrupt must be enabled and the peripheral interrupt as well and the global interrupts.
USART1->CR1 |= USART_CR1_TXEIE | USART_CR1_RXNEIE; // Enable the Transmit Data Register Empty Interrupt register and data received interrupt
// Enable the Tx, Rx, USART1 as a whole block
USART1->CR1 |= (USART_CR1_RE | USART_CR1_TE | USART_CR1_UE);
// Enable the USART1 Global interrupt on NVIC "Nested Vectored Interrupt controller" side. The NVIC is the interrupt processing unit in the MCU.
NVIC_EnableIRQ(USART1_IRQn); // This function's name can't be changed!
}
// This is a global interrupt service routine, any flag from the USART1 will lead to the same ISR, to distinguesh which is which we check the the flags and if one is set then this what caused the interrupt
void USART1_IRQHandler(void) // This function's name must be the same as it's defined in the main libraries
{
// Check if we are here because we Received Data or simply the "RXNE flag is set".
if(USART1->SR & USART_SR_RXNE) // If Rx is Not Empty, or if we received Data, The USART1->SR register is going to change as it is controlled by the hardwart and we compare it to the value of the register USART_SR_RXNE which indicates a 1 at bit5
{
char temp = USART1->DR; // Read the 8bit data received fron the data register into a char called temp
USART1->DR = temp; // Put the same data in the data register to be resent again, here the data registers are clled shadow registers they are not the same registers from the hardware prospective but from programming prospective we use the same registers
while(!(USART1->SR & USART_SR_TC))
{
// Wait while the transmission completes and indicate the waiting process by flashing the RED led indicating data being sent.
GPIOB->BSRR = GPIO_BSRR_BR10; // When not ready to accept more data (e.g. while transmitting data process) turn of the Blue LED
GPIOB->BSRR = GPIO_BSRR_BS1;
delay(10000);
GPIOB->BSRR = GPIO_BSRR_BR1;
}
}
// Check if we are here because the TXEIE is set "OR the Transmit complete" meaning we are ready to accept more data to transmit
if(USART1->SR & USART_SR_TXE)
{
// Handle transmit complete here: (Blink an LED)
GPIOB->BSRR = GPIO_BSRR_BS10; // When Ready to accept more data
}
else
{
GPIOB->BSRR = GPIO_BSRR_BR10; // When not ready to accept more data (e.g. while transmitting data process)
}
}
void portsEnable(void) /* Enable PortA and PortB */
{
// Enable clock for Ports (A & B) on "APB2" Bus.
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; // Enable PortA Clock
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; // Enable PortB Clock
}
void pinsConfig(void) //Configure the used pins.
{
//Set pin "PB1" as output push-pull (Red LED)
GPIOB->CRL |= ((1<<4) | (1<<5)); //Set Pin to Output 50Mhz max speed
GPIOB->CRL &= ~((1<<6) | (1<<7)); //Configure Pin as Push-Pull
//Set Pin "PB9" as Input Pulled-Up (Push Button Pin)
GPIOB->CRH &= ~(1<<6); //Set PB9 to input "pullup|pulldown"
GPIOB->CRH |= (1<<7);
GPIOB->ODR |= (1<<9); //Set PB9 input pin as Pull-up pin.
//Set pin "PB10" as output push-pull (Blue LED)
GPIOB->CRH |= ((1<<9) | (1<<8)); //Set Pin to Output 50Mhz max speed
GPIOB->CRH &= ~((1<<11) | (1<<10)); //Configure Pin as Push-Pull
//Set pin "PB11" as output push-pull (Green LED)
GPIOB->CRH |= ((1<<12) | (1<<13)); //Set Pin to Output 50Mhz max speed
GPIOB->CRH &= ~((1<<14) | (1<<15)); //Configure Pin as Push-Pull
//Set pin PA0 as Analog input
GPIOA->CRL &= ~((1<<0) | (1<<1)); // Make sure the Mode registers are 00 for input
GPIOA->CRL &= ~((1<<2) | (1<<3)); // Set the CNF registers to 00 for input analog
} // End PinsConfig()
void delay(uint32_t delay) /* Psudo-delay in Milliseconds */
{
for(uint32_t i = 0; i <= delay; i++)
{
// Looping to delay!
}
}
Maybe below link is helpful for you:
stm32 dead lock

How can you get Eclipse CDT to understand MSPGCC (MSP430) includes?

I'm using Eclipse and CDT to work with the mspgcc compiler, it compiles fine, but the code view highlights all my special function registers as unresolved.
I've made a C project where the compiler is "msp430-gcc -mmcu=msp430x2012", and that's set to look for includes in /usr/msp430/include/. I've set the linker to "msp430-gcc -mmcu=msp430x2012", and that's set to look fo libraries in /usr/msp430/lib/. I've set the assembler to "msp430-as". I've told eclipse it's making an elf and I've disabled automatic includes discovery to not find the i686 libraries on my linux box (stupid eclipse!).
Here's the code:
#include <msp430.h>
#include <signal.h> //for interrupts
#define RED 1
#define GREEN 64
#define S2VAL 8
void init(void);
int main(void) {
init(); //Setup Device
P1OUT = GREEN; //start with a green LED
_BIS_SR(LPM4_bits); //Go into Low power mode 4, main stops here
return(1); //never reached, surpresses compiler warning
}
interrupt (PORT1_VECTOR) S1ServiceRoutine(void) {
//we wake the MCU here
if (RED & P1IN) {
P1OUT = GREEN;
} else {
P1OUT = RED;
}
P1IFG = 0; //clear the interrupt flag or we immidiately go again
//we resume LPM4 here thanks to the RETI instruction
}
void init(void) {
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
/*Halt the watchdog timer
P1DIR = ~S2VAL; //Set LED pins as outputs and S2 as input
P1IES = S2VAL; //interrupt on High to Low
P1IE = S2VAL; //enable interrupt for S1 only
WRITE_SR(GIE); //enable maskable interrupts
}
All the variables defines in the mspgcc includes such as P1OUT and WDTCTL show up in the problems box as "not resolved", but remember it builds just fine. I've even tried explicitly including the header file for my chip (normally msp430-gcc does this via msp430.h and the -mmcu option).
I resolved this issue by explicitly including the msp430g2553.h file
#include <msp430g2553.h>
I resolved the issue by following the instructions here