I am trying to blink the led on GPIO PA5 port, every time when PC13 Button is clicked. However, it does not work. Could you please advice, how can i solve the problem?
main.c - main program
#include "main.h"
#include "stm32l0xx_hal.h"
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
while (1)
{
}
}
GPIO port conficuration section. PA5 and PC13 ports are configured.
Interrupt on EXTI13 enabled.
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
/*Configure GPIO pin : PC13 */
GPIO_InitStruct.Pin = GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/*Configure GPIO pin : PA5 */
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* EXTI interrupt init*/
HAL_NVIC_SetPriority(EXTI4_15_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI4_15_IRQn);
}
stm32l0xx_it.c - interrupt file. IRQ handler and Callback function defined.
void EXTI4_15_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
HAL_Delay(500);
}
Best regards,
I don't understand what you want to do.
If you want to change the state of your LED on each push button event, you don't need to put a delay in the HAL_GPIO_EXTI_Callback. It's not a good practice in firmware development. IRQs are supposed to manage events quickly. Their processes have a higher priority than the program execution (here, your main).
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == GPIO_PIN_13)
{
HAL_GPIO_TogglePin (GPIOA, GPIO_PIN_5);
}
}
If you want to start/stop blinking your LED based on push button events, you need to use a timer (e.g. the button start a timer, each timer elapsed irq toggles PA5).
In MX_GPIO_Init function, you have to call HAL_GPIO_WritePin after the PA5 initialization (HAL_GPIO_Init).
Take a look to your hardware before setting a pullup on PA13.
I advise you to download STM32Cube. They are lot of code samples. An example shows how to configure external interrupt lines to blink a LED on button events (repository path: ...\STM32Cube\Repository\STM32Cube_FW_L0_V1.8.0\Projects\STM32L073RZ-Nucleo\Examples\GPIO\GPIO_EXTI).
HAL_Delay() will not work until you change priority of exti irq to be higher then priority of systick irq. In your implementation, I assume, default priorities are 0 for both and HAL_Delay() hangs because you use it in same isr priority. Try to change exti irq priority to 1.
Related
Good morning,
I am dealing with a problem of turing off interrupts on selected pin while another one is set. My MCU is stm32f4xx.
I mean that, I have set PC0, PC1, PC2, PC3, PB14, PB15 on GPIO_MODE_IT_FALLING detect and when I set the pin PA1, PA2, PA3, PA4 as GPIO_MODE_IT_RISING_FALLING detect, PC and PB do not works.
If PC-PB is set individually it works. If I set additional PA1-4 the pins PC-PB just forgot about interrupt. Code below for every PC0-3 and PB14-PB15:
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = FAULT1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
HAL_NVIC_SetPriority(EXTI0_IRQn, 5, 0); // EXTI0_IRQn changes on dependently on selected pins e.g. EXTI15_10_IRQn
HAL_NVIC_EnableIRQ(EXTI0_IRQn); // here the same
and after I iterate for every pin PC0-3 and PB14-15 I am using the same pattern for PA2-PA4 like this:
GPIO_InitTypeDef GPIO_InitStruct = { 0 };
GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* EXTI interrupt init*/
HAL_NVIC_SetPriority(EXTI1_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(EXTI1_IRQn);
HAL_NVIC_SetPriority(EXTI2_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(EXTI2_IRQn);
HAL_NVIC_SetPriority(EXTI3_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(EXTI3_IRQn);
HAL_NVIC_SetPriority(EXTI4_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(EXTI4_IRQn);
and then the interrupt on pins PC, PB disappear. Only iterrupts from PA works fine.
How to write a program that allows PC, PB and PA interrupts works?
I am also using FreeRTOS, maybe here is a problem?
Sadly this is a "feature" of the STM32 family. What you want cannot be done.
You have to arrange your pinout to account for this: You can only have an interrupt on one letter for each number (eg: PA2 or PB2 not both).
Another limitation is that numbers 5-9 and 10-15 share interrupts. You can have interrupts on eg: PA5,PB6,PA7,PB8,PC9 but they will cause the same handler to run. Obviously you can then read the GPIO input in the handler but if the signal is momentary and has gone away by the time the handler runs you will not know which signal occurred.
I'm working with an STM32L073RZ CPU running MbedOS 5.11.2. Eventually I aim to get this working in a very low-power mode (STOP mode) that will be awoken with either an RTC interrupt or an interrupt from a peripheral device on pin PA_0 (WAKEUP_PIN_1). At the moment I am simply attempting to setup PA_0 as an interrupt using the STM32 HAL API. Please see my code below:
#include "mbed.h"
#define LOG(...) pc.printf(__VA_ARGS__); pc.printf("\r\n");
DigitalOut led(LED1);
Serial pc(USBTX, USBRX);
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
led = !led;
}
int main()
{
pc.baud(9600);
led = 1;
// GPIO SETUP
LOG("Enabling GPIO port A clock");
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
LOG("Initialising PA_0");
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// NVIC SETUP
LOG("Setting IRQ Priority");
HAL_NVIC_SetPriority(EXTI0_1_IRQn, 0, 1); // Priorities can be 0, 1, 2, 3 with lowest being highest prio
LOG("Enabling IRQ");
HAL_NVIC_EnableIRQ(EXTI0_1_IRQn);
LOG("Going into STOP mode");
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFE);
}
As you can see, the code is broken into two sections: GPIO setup and NVIC setup. My issue is as follows:
If I perform GPIO setup before NVIC setup then the program seems to hang on HAL_NVIC_SetPriority(), however, if I perform NVIC setup before GPIO setup then the code seems to hang on HAL_NVIC_EnableIRQ().
I am completely stumped as to what is causing this. Any insight is greatly appreciated.
You don't need to do this manually. As long as you run Mbed OS in tickless mode (set MBED_TICKLESS=1 macro in your mbed_app.json) the MCU will automatically enter stop mode whenever all threads are idle. If you want to wake up you can either use an InterruptIn on the pin or use a LowPowerTicker.
If you're looking for the absolute lowest power modes, you can use the standby feature (without RAM retention) for which there's a library here: stm32-standby-rtc-wakeup.
I have easy understanding Question. Whet I do initialize my STM32 timer for 1 sek counts (TIM8, Prescaller = 16800-1, Period = 10000-1) and want to debug it (measure a pin output frequency) - it a timer frequency the same frequency like I can observe it on oscilloscope?
And it is a right configuration for TIM8 timer Interrupt?
void Second_timer_Init() {
GPIO_InitTypeDef GPIO_InitStructure; //GPIO Init structure definition
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); //Enables AHB1 peripheral clock for GPIOC
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE); //Enables AHB1 peripheral clock for TIM2
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; //Specifies the GPIO pins to be configured
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //Specifies the operating output type for the selected pins
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //GPIO Alternate function Mode
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //Specifies the operating Pull-up/Pull down for the selected pins
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //Specifies the speed for the selected pins
GPIO_Init(GPIOC, &GPIO_InitStructure); //Initializes the GPIOA peripheral
TIM_TimeBaseInitTypeDef Timer_InitStructure; //TIM8 Time Base Init structure definition
TIM_OCInitTypeDef Output_ChannelInit; //TIM8 Output Compare Init structure definition
GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_TIM8); // PC6 -> Connect TIM8 pins to AF3
Timer_InitStructure.TIM_Period = 10000 - 1; //Specifies the period value (Orig 1 Sek: 10000-1)
Timer_InitStructure.TIM_Prescaler = 16800-1; //Specifies the prescaler value used to divide the TIM clock (Orig 1 Sek: 16800-1)
Timer_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //Specifies the clock division (0)
Timer_InitStructure.TIM_CounterMode = TIM_CounterMode_Up; //Specifies the counter mode
TIM_TimeBaseInit(TIM8, &Timer_InitStructure); //Initializes the TIM8 Time Base Unit peripheral
// TIM_OCStructInit(&Output_ChannelInit);
Output_ChannelInit.TIM_OCMode = TIM_OCMode_PWM1; //Specifies the TIM8 PWM mode
Output_ChannelInit.TIM_OutputState = TIM_OutputState_Enable;//Specifies the TIM8 Output Compare state
Output_ChannelInit.TIM_Pulse = 0; //Specifies the pulse value to be loaded into the Capture Compare Register
Output_ChannelInit.TIM_OCPolarity = TIM_OCPolarity_Low; //Specifies the output polarity
TIM_OC1Init(TIM8, &Output_ChannelInit); //Initializes the TIM8 Channel1
TIM_OC1PreloadConfig(TIM8, TIM_OCPreload_Enable); //Enables the TIM2 peripheral Preload register on CCR1
TIM_ARRPreloadConfig(TIM8, ENABLE); //Enables TIM2 peripheral Preload register on ARR
TIM_Cmd(TIM8, ENABLE); //Enables the specified TIM8 peripheral
TIM_CtrlPWMOutputs(TIM8, ENABLE); //Enables the TIM peripheral Main Outputs ?
TIM8->CCR1 = 5000; //Set duty cycle to 50%
TIM_ClearITPendingBit(TIM8, TIM_IT_Update); //Clears the TIM8 interrupt pending bits
TIM_ITConfig(TIM8, TIM_IT_Update, ENABLE); //Enables the specified TIM8 interrupts
NVIC_InitTypeDef NVIC_InitStructure; //NVIC Init Structure definition
NVIC_InitStructure.NVIC_IRQChannel = TIM8_CC_IRQn; //Specifies the IRQ channel to be enabled
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;//Specifies the pre-emption priority for the IRQ channel specified in NVIC_IRQChannel (0-15)
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00; //Specifies the subpriority level for the IRQ channel specified in NVIC_IRQChannel (0-15)
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //Specifies whether the IRQ channel defined in NVIC_IRQChannel will be enabled
NVIC_Init(&NVIC_InitStructure); //Initializes the NVIC peripheral
}
IRQ Handler
void TIM8_CC_IRQHandler(){
if (TIM_GetITStatus(TIM8, TIM_IT_Update) != RESET) //Checks whether the TIM8 interrupt has occurred
{
TIM_ClearITPendingBit(TIM8, TIM_IT_Update); //Clears the TIM8 interrupt pending bits
TIM3->CCR1 = 500; //Debug
}
else{
TIM3->CCR1 = 0; //Debug
}
}
As I see you change the TIM3 registers in the TIM8 interrupt.
Secondly you check for the wrong event in your interrupt routine (this routine is invoked then the CC event occurs not the UG event. Same when you set the interrupts. You enable the UG interrupt but serve the CC one. Some of the uC models have those interrupt vectors shared some not.
BTW What is the point of using HAL library if you change the registers?
I am using the STM32F429I-Discovery board, the board has a pushbutton connected to PA0, which in turn is connected to External Interrupt Line 0 (EXTI0).
Using the HAL Libraries, I can toggle a LED either on the Falling Edge or on the Rising edge using external interrupts. Eg, the LED either changes state as soon as I press the pushbutton, or only once I release the pushbutton.
What I want to do is to Interrupt on the Rising edge, start a timer, and then interrupt on the falling edge again, to stop the timer. I have got no idea how to achieve this?
There is also an option to trigger on both rising and falling edges. I do not know if there should only be one interrupt, and I then figure out if it was a rising or falling edge (probably by accessing the registers directly), or should there be two configured interrupts - One as Rising Edge and one as Falling Edge?
Below are the external interrupt code; firstly to set a GPIO up as an external interrupt, then to detect the interrupt and then to handle the interrupt (callback).
static void EXTILine0_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable GPIOA clock */
__HAL_RCC_GPIOA_CLK_ENABLE();
/* Configure PA0 pin as input floating */
GPIO_InitStructure.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Pin = GPIO_PIN_0;
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Enable and set EXTI Line0 Interrupt to the lowest priority */
HAL_NVIC_SetPriority(EXTI0_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}
/* Clears the interrupt after calling this I think */
void EXTI0_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(KEY_BUTTON_PIN);
}
/**
* #brief EXTI line detection callbacks
* #param GPIO_Pin: Specifies the pins connected EXTI line
* #retval None
*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == KEY_BUTTON_PIN)
{
/* Toggle LED3 */
BSP_LED_Toggle(LED3);
}
}
Can someone please point out how I can achieve this?
What you're looking for is called "input capture" and can be achieved with a timer directly without the need for external interrupts. On the STM32F429 PA0 is internally mapped to Timer 2 Channel 1.
The sConfigIC structure is responsible for handling input capture related configuration stuff.
The initialization looks something like this:
/* TIM2 init function */
void MX_TIM2_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig;
TIM_MasterConfigTypeDef sMasterConfig;
TIM_IC_InitTypeDef sConfigIC;
/* Peripheral clock enable */
__TIM2_CLK_ENABLE();
/* Peripheral interrupt init*/
HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
/**TIM2 GPIO Configuration
PA0/WKUP ------> TIM2_CH1
*/
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
htim2.Instance = TIM2;
htim2.Init.Prescaler = 0;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 0xFFFFFFFF;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_Base_Init(&htim2);
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig);
HAL_TIM_IC_Init(&htim2);
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig);
/* Input capture stuff HERE
Change polarity as needed */
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_BOTHEDGE;
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = 0;
HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1);
}
And further the interrupt function:
/* IRQ */
void TIM2_IRQHandler(void)
{
// Check for interrupt flags here
}
Within the interrupt you've got to check for the CC1IF flag. The timer value gets stored in the capture and compare register called CCR1.
/edit
Don't forget to start the timer and input capture channel with:
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);
This enables the timer, the according channel for input capture and the interrupt.
First, you have to setup a timer, e.g.
TIM_HandleTypeDef htim1;
void TIM1_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig;
TIM_MasterConfigTypeDef sMasterConfig;
htim1.Instance = TIM1;
htim1.Init.Prescaler = 71;
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = 65535;
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.RepetitionCounter = 0;
HAL_TIM_Base_Init(&htim1);
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig);
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig);
}
Code is taken from an STM32F1, so maybe you have to adapt a little, just have a look in the HAL handbook.
The interrupt for rising and falling edge is the same, so you have to check the state of the pin in your interrupt handler.
To start the timer
HAL_TIM_Base_Start(&htim1);
and to stop
HAL_TIM_Base_Stop(&htim1);
the counter value is stored in
TIM1->CNT
A bit of background: Using the STM32F429I the code below is to display how long you press the blue user button for, the count is given as milliseconds. The PCB has a hardware debounce circuit so the fastest response I was able to get is around 50ms.
As stated earlier PA0 is connected to EXTILine0.
I set the PA0 line up to interrupt on both rising and falling edges.
static void EXTILine0_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable GPIOA clock */
__HAL_RCC_GPIOA_CLK_ENABLE();
/* Configure PA0 pin as input floating */
GPIO_InitStructure.Mode = GPIO_MODE_IT_RISING_FALLING;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Pin = GPIO_PIN_0;
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Enable and set EXTI Line0 Interrupt to the lowest priority */
HAL_NVIC_SetPriority(EXTI0_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}
When a interrupt then occurs, I read the amount of counts that are currently stored in HAL_GetTick(), this function clocks every 1 millisecond. I also read whether the pin is high or low to determine if the interrupt was on a falling or on a rising edge.
uint16_t beginCount;
uint16_t stopCount;
void EXTI0_IRQHandler(void)
{
uint16_t var;
var = HAL_GetTick();
uint16_t calcCount = 0;
unsigned char buffer[10];
BSP_LCD_Clear(LCD_COLOR_WHITE);
// The Pin Goes high when the pushbutton is pressed.
if (HAL_GPIO_ReadPin(GPIOA, KEY_BUTTON_PIN) == 0x01)
{
beginCount = 0;
beginCount = var;
BSP_LCD_SetTextColor(LCD_COLOR_GREEN);
BSP_LCD_DisplayStringAtLine(6, "Rising Edge" );
}
else
{
stopCount = 0;
stopCount = var;
BSP_LCD_SetTextColor(LCD_COLOR_RED);
BSP_LCD_DisplayStringAtLine(7, (uint8_t*)"Falling Edge");
// Calculate Counts and covert to seconds - What if the counter overflows?
calcCount = stopCount - beginCount;
sprintf(buffer, "%d", calcCount); // Convert the integer to string and put it in variable buffer
BSP_LCD_DisplayStringAtLine(8, (&buffer) ); // Display the value stored at buffer's location
}
HAL_GPIO_EXTI_IRQHandler(KEY_BUTTON_PIN);
}
Lastly the interrupt callback triggers and just toggles the LED on the board.
The counter can only go to something like 65 seconds, after that it would overflow and my 'calculated' time would be incorrect. This methods works OK for what I intend to do with it. I want to measure 20-300 milliseconds with a accuracy of a few milliseconds. I still have to put in a catch for if the timer overflows between two measurements.
Anything fundamentally wrong with this approach? I am not very experienced with C, and not at all with STM32.
I develop on a map I'm working on STM32 and USART interrupts. After configuring the USART1 and make Enable receive interrupt. The problem that the interruption of reception have no detected????
Such a question is difficult to answer without knowing which specific processor you are using, which board you are using, and/or which compiler you are using. But in an attempt to be helpful, here's my code.
Here's my GPIO and NVIC initialization code using Sourcery CodeBench Lite with an STM32F4 processor mounted on a custom board.
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_USART3);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_USART3);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// Enable the USART RX Interrupt
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
Of course your settings will vary depending on your processor, board and interrupt priority.
Here's my interrupt handler code. In my development environment, this handler is declared in my startup assembly file as a weak reference to Default_Handler...
Default_Handler:
b .
/* ... */
.word USART3_IRQHandler
/* ... */
.weak USART3_IRQHandler
.thumb_set USART3_IRQHandler,Default_Handler
... so as long as I provide a new declaration and implementation of this interrupt handler, the weak reference will be replaced. Here's what my code looks like.
//Interrupt handler declaration
void USART3_IRQHandler();
If you are using C++ you will need to declare it as follows:
//Interrupt handler declaration in C/C++
#ifdef __cplusplus
extern "C" {
#endif
void USART3_IRQHandler();
#ifdef __cplusplus
}
#endif
And here's the interrupt handler implemenation.
//Interrupt handler implementation
void USART3_IRQHandler()
{
//handle interrupt
}
Here's short and simple code to configure STM32 USART (USART3) and Interrupt Handler.
Configure and Init
void Init_USART3()
{
// PB.11 = RX Floating Input
// PB.10 = TX Alternate function output Push-pull 50 MHz
RCC->APB2ENR = RCC->APB2ENR | (RCC_APB2ENR_IOPBEN);
RCC->APB1ENR |= RCC_APB1ENR_USART3EN; // enable clock for USART3.
GPIOB->CRH = GPIOB->CRH & 0xFFFF00FF;
GPIOB->CRH = GPIOB->CRH | 0x00004B00;
USART3->BRR =72000000/9600; // set baudrate.
USART3->CR1 |= (USART_CR1_RE | USART_CR1_TE); // RX, TX enable.
USART3->CR1 |= USART_CR1_UE; // USART3 enable.
USART3->CR1 |= USART_CR1_RXNEIE; // UART3 Receive Interrupt Enable.
// Enable interrupt fromUSART1(NVIC level)
NVIC_EnableIRQ(USART3_IRQn);
}
Handle Receive Interrupt
void USART3_IRQHandler()
{
if(USART3->SR & USART_SR_RXNE)
{
// Do Something
}
}
Make sure you don't call HAL_UART_Transmit() on the same usart that you try interrupt. It is because this function calls UART_WaitOnFlagUntilTimeout() which disables the interrupt. The trace printf() that user7404301 mentioned above most likely calls it.
SAMPLE CODING TO HANDLE RECEIVE INTERRUPT
//USART1 Interrupt Handler
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)//enter interrupt when STM32 receice data.
{
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
USART_Temp_Data = (unsigned char) USART_ReceiveData(USART1); //receive a char
}
}
I had the same question with Eclipse(GCC)before and finally I found out the problem.The problem is not at the code but the "trace_printf", if you are using this API to print any details while running, the "trace_printf" will break the uart and your receive interrupt will never ocurrs.So, have a try, not use it and set breakpoints to see what you have recveived.