Currently, I am working on optimizing current consumption by using STOP Mode of the STM32L053C6T6 processor.
I'm facing a problem that I can not get through, and I'm very happy if you can help.
First of all, I would like to explain the algorithm in a very simplified way.
In the while loop, I print to Pc "STARTED" through the UART-Serial converter. Next, I set the RTC alarm to 10 seconds later. And the finally I sleep the MCU by using STOP MODE. After 10 seconds, MCU wakes up properly. So far everything is normal. After MCU wake up, I call the System Clock Config function. I print "woken-up" on the PC screen through UART. I can work this way forever But I do not like the current that circuit consume.
To reduce the power consumption, I set all the pins to analog before entering sleep mode. this method worked very well on reducing current consumption. But after all the pins are analog and MCU goes sleep and wake up, the MCU can not send to string to PC. I think UART Module does not work properly...
But I/O's and systick timer are running. I can understand this by toggling the LED in a certain delay(with HAL_DELAY)
Why I can not make it work with reinit all peripherals?
Here is my main code
int main(void){
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_ADC_Init();
MX_I2C1_Init();
MX_RTC_Init();
MX_TIM22_Init();
MX_USART1_UART_Init()
MX_USART2_UART_Init();;
Init_RTC();
HAL_Delay(500);
while(1)
{
printf("Started\n\r");
for(uint16_t count1 = 0;count1<25;count1++){
HAL_GPIO_TogglePin(STATE_LED0_GPIO_Port,STATE_LED0_Pin);
HAL_Delay(25);
}
SetAlarm(10);
EnterStopMode();
printf("Woken-Up\n\r");
HAL_Delay(1000);
}
}
void EnterStopMode(void){
GPIO_InitTypeDef GPIO_InitStruct;
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_All;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* Disable GPIOs clock */
__HAL_RCC_GPIOA_CLK_DISABLE();
__HAL_RCC_GPIOB_CLK_DISABLE();
// STOP Moda girme komutu
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
HAL_Delay(1000);
SystemClock_Config();
HAL_Delay(500);
MX_GPIO_Init();
MX_USART2_UART_Init();
Solved
Well, I checked the Hal functions line by line. And I saw that after first peripheral initialization (uart,i2c,adc etc.), Hal functions do not allow re-init again by checking that particular peripherals instant state.
For example, In HAL_UART_Init(&huart2) function, In order to Init the low level hardware: (GPIO,CLOCK) the instant uart modules state must be UART_STATE_RESET.
In here
if(huart->gState == HAL_UART_STATE_RESET)
{
/* Allocate lock resource and initialize it */
huart->Lock = HAL_UNLOCKED;
/* Init the low level hardware : GPIO, CLOCK */
HAL_UART_MspInit(huart);
}
To overcome this problem, I reset that particular state of peripheral init. Because without not clearing those flags, uart init functions does not enter HAL_UART_MspInit(huart);
I know that is bulky solution, but it works for now.
void EnterStopMode(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/* Configure all GPIO port pins in Analog Input mode (floating input trigger OFF) */
GPIO_InitStruct.Pin = GPIO_PIN_All;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* Disable GPIOs clock */
__HAL_RCC_GPIOA_CLK_DISABLE();
__HAL_RCC_GPIOB_CLK_DISABLE();
HAL_TIM_Base_Stop_IT(&htim22);
HAL_ADC_Stop_IT(&hadc);
/* Enter Stop Mode */
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
/* init the SYS Clocks */
SystemClock_Config();
/*Init IO's */
MX_GPIO_Init();
/* Clear Peripheral States for MspInit *7
huart1.gState = HAL_UART_STATE_RESET;
huart2.gState = HAL_UART_STATE_RESET;
hi2c1.State = HAL_I2C_STATE_RESET;
hadc.State = HAL_ADC_STATE_RESET;
MX_USART2_UART_Init();
MX_USART1_UART_Init();
MX_I2C1_Init();
MX_RTC_Init();
MX_TIM22_Init();
MX_ADC_Init();
HAL_ADCEx_Calibration_Start(&hadc,ADC_SINGLE_ENDED);
}
Related
I'm working on an stm32l467 and trying to run an ISR when i push the user-push-button. Everything looks to be setup correctly. I have looked at the registers in the debugger (Keil uV) and everything looks good, but when i push the button I end up in the default handler and can't understand why the handler is not running.
Running in the debugger i can see that when i push the button, i get an interrupt-pending (EXTI->PR1) flag, but the code then jumps to the the default handler. I can't see what i'm missing. I know there are easier ways to setup interrupts using the HAL layer, i'm just trying to understand what registers must be accessed from a low-level.
Can anyone suggest a missing step to this?
#include <stm32l4xx.h>
#define DELAY 1
void delay1Hz(void);
bool buttonInterrupt = false;
int main(void)
{
__disable_irq();
/* Configure the clocks */
RCC->CR &= 0xFFFFFF07; //Clear ~MSIRANGE bits and MSIRGSEL bit
RCC->CR |= 0x00000088; //Set MSI to 16MHz and MSIRGSEL bit
RCC->AHB2ENR |= 0x00000001; //Enable PA5 clocks
/* Enable PA0 for output */
GPIOA->MODER &= 0xFFFFF3FF; //Clear GPIOA[5] MODER bits
GPIOA->MODER |= 0x00000400; //Enable GPIOA[5] for output
RCC->AHB2ENR |= 0x4; //ENABLE GPIOC port clk
GPIOC->MODER &= 0xF3FFFFFF; //Clear GPIOC[13] for input mode
RCC->APB2ENR |= 1; //Enable SYSCFG clk
SYSCFG->EXTICR[3] &= ~0x00F0; //CLEAR_BIT the EXTI[13] bits
SYSCFG->EXTICR[3] |= 0x20; //Enable GPIOC for EXTI[13]
EXTI->IMR1 |= 0x2000; //Unmask EXTI13
EXTI->FTSR1 |= 0x2000; //Enable falling edge trigger on pb
NVIC_EnableIRQ(EXTI15_10_IRQn); //Enable EXTI15-to-10 interrupts
__enable_irq();
for (;;)
{
if(buttonInterrupt == true) {
//flash LED's (doesn't get here)
}
}
}
void initTim2() {
//timer 2 code - not causing a problem
}
void delay1Hz() {
//delay code - not interrupt controlled
}
/* This doesn't run */
void EXTI15_10_IRQHandler(void) {
buttonInterrupt = true;
EXTI->PR1 = 0x2000;
}
Never mind: There seems to be some problem with a delay i have with timer-2. It's not using interrupts, so i'm surprised it's causing trouble. But if i take it out and use a different delay, the interrupt from the above code works fine. It's an odd one.
I would like to use the pin PC3 as an external interrupt. Whenever I enable the interrupt I end up in the infinite loop.
This is how I init a gpio and its interrupt:
__HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/* EXTI interrupt init*/
HAL_NVIC_SetPriority(EXTI3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI3_IRQn);
I have checked hardware and all signals are like they should be.
I tried PB0 and PC3 and the result is the same.
Anyone who knows how to play with stm32l4 and exti?
The infinite loop:
Default_Handler:
Infinite_Loop:
b Infinite_Loop
.size Default_Handler, .-Default_Handler
I dont even reach an interrupt here (I have a break point there)
void EXIT3_IRQnHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_3);
if(!HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_3))
{
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_7);
HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_14);
}
EXTI_ClearITPendingBit(EXTI3_IRQn);
}
Maybe that is important to mention that I also have SPI configuration in the same project (SPI1).
If ISR name is not correct it will use some default error code (its name depends on configuration), as happens in your case.
In my code its named EXTI3_IRQHandler not EXTI3_IRQnHandler.
Check in your startup file (in my setup it is called startup_stm32l432xx.s) for ISR names to be used.
I've bought an STM32F411 nucleo board and now I'm trying to understand various bits and pieces of the HAL. Starting with external interrupts seemed to be a good idea, because the board has a push button which is connected to PC13. So I've set up a simple toggle-the-frequency blinky. The code below is a bit simplified:
#define LED_PIN GPIO_PIN_5
#define BTN_PIN GPIO_PIN_13
static uint32_t blink_period = 250;
int main(void)
{
HAL_Init();
SystemClock_Config();
__GPIOA_CLK_ENABLE();
GPIO_InitTypeDef pinConfig;
pinConfig.Pin = (LED_PIN);
pinConfig.Pull = GPIO_NOPULL;
pinConfig.Mode = GPIO_MODE_OUTPUT_PP;
pinConfig.Speed = GPIO_SPEED_FAST;
HAL_GPIO_Init(GPIOA, &pinConfig);
__GPIOC_CLK_ENABLE();
pinConfig.Pin = (BTN_PIN);
pinConfig.Pull = GPIO_NOPULL;
pinConfig.Mode = GPIO_MODE_IT_FALLING;
pinConfig.Speed = GPIO_SPEED_LOW;
HAL_GPIO_Init(GPIOC, &pinConfig);
HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0x0F, 0x00);
HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
while (1)
{
HAL_GPIO_TogglePin(GPIOA, LED_PIN);
HAL_Delay(blink_period);
}
}
void EXTI15_10_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(BTN_PIN);
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == BTN_PIN)
{
if (blink_period == 500)
{
blink_period = 250;
}
else
{
blink_period = 500;
}
}
}
When I push the button, an interrupt is generated and the blinky frequency changes from 1 to 2 Hz (or vice-versa). This works as intended, but why? I forgot to clear the pending interrupt flag, so the ISR should be called over and over. The datasheet clearly states that
When the selected edge occurs on the external interrupt line, an interrupt request is generated. The pending bit corresponding to the interrupt line is also set. This request is
reset by writing a ‘1’ in the pending register.
Reading a bit further reveals that this is a bit different for events:
When the selected edge occurs on the event line, an event pulse is generated. The pending bit corresponding to the event line is not set.
However, I'm not setting the button pin mode to any of the GPIO_MODE_EVT_... modes so I'm not using the event mechanism (to be honest I don't yet know what that even is - I just think that I'm not using it. Any hints are welcome).
So somewhere I should have to call void HAL_NVIC_ClearPendingIRQ (IRQn_Type IRQn), shouldn't I? It seems that clearing the flag by software is not necessary, because the ISR is not called more than once per falling edge. I've added a breakpoint in HAL_GPIO_EXTI_Callback to verify this.
Edit
As mentioned in the comments, the flag clearing code is in ST's implementation of the GPIO interrupt handler:
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);
}
}
This handler needs to be called by the actual ISR (which is done in my code) and it clears the pending flag corresponding to the GPIO_Pin argument. So I have to write an ISR which sorts out which flags are set, and call HAL_GPIO_EXTI_IRQHandler for each, which in turn calls my HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin), again with the pin as an argument. For each external interrupt, the pin number would get checked some ~3 times (in the ISR, in the handler and in the callback)!
If that is the solution, I want my problem back.
You don't have to call HAL_NVIC_ClearPendingIRQ (IRQn_Type IRQn) because the pending bit in the NVIC will be cleared automatically upon entering HAL_GPIO_EXTI_IRQHandler.
The HAL_GPIO_EXTI_IRQHandler() implementation clears the pending bit in the peripheral, not in the NVIC. If it didn't clear the pending bit by calling __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin), then the handler would be called again and again. The point is that you must distinguish between the interrupt pending bit in the peripheral and the pending bit in the NVIC.
I'm trying to set up an external interrupt on my LPC812 uC. I've made the following code
#include "LPC8xx.h"
#define RLED 7 // red LED
bool pause = false;
void PININT0_IRQHandler(void)
{
pause = !pause;
}
int main(void) {
LPC_GPIO_PORT->DIR0 |= 1<<RLED; // set pin as output
LPC_GPIO_PORT->SET0 = 1<<RLED;
NVIC_EnableIRQ(PININT0_IRQn);
while (1)
{
if(!pause)
{
LPC_GPIO_PORT->CLR0 = 1<<RLED;
}
}
}
But it isn't working. Am I missing something?
I'm not familiar with NXP MCUs.
But at least place break piont inside PININT0_IRQHandler, to understand clearly that interrupt is not generated.
Also it will be nice to clear interrupt flag inside handler.
Some peripherals need interrupt permission in peripheral registers in addition to NVIC setup.
Did you setup input pin somewhere?
Your code only initialize GPIO 7 pin as output.
I have a board that is connected to USB on a STM32F107 with the following pins
USB_OTG_VBUS : PA9
USBDM : PA11
USBDP : PA12
I have a project that needs to use both Virtual Com Port and USB Mass Storage. It needs to re-enumerate the USB then do a software reset to enable the different USB class.
I have tried various different things to get it to re-enumerate but so far have been unable to, the only way to re-enumerate is to unplug usb cable.
These are some of the functions i have tried with no success
USB_OTG_DisableGlobalInt(&USB_OTG_dev);
USB_OTG_WRITE_REG32(&USB_OTG_dev.regs.GREGS->GINTSTS, 0xBFFFFFFF);
USB_OTG_CoreReset(&USB_OTG_dev);
USBD_DeInit(&USB_OTG_dev);
DCD_DevDisconnect(&USB_OTG_dev);
NVIC_SystemReset();
Would anyone have any ideas on how to get the USB to re-enumerate when it is configured with only these 3 pins for the STM32F107?
If you're using a demo board, it has the functionality to disconnect the USB through a microcontroller pin. If you're not using a demo board, you need to come up with that ability yourself, by disconnecting the pull-up resistor on the USB_DM/USB_DP line...
Before initializing USB peripheral, configure D+ pin (USBP) as GPIO output push-pull and set low (0V) for 5ms. Then initiate standard USB configuration including GPIO. After this procedure USB host recognizes new device and starts enumeration.
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_ResetBits(GPIOA, GPIO_Pin_12);
delay_ms(5);
//call your USB Init here
Worked for me.
source
Had a similar problem. Try this:
USB_OTG_dev.regs.GREGS->GCCFG = 0;
Wait a bit and then init the USB again.
I used the answer from #viteo and tweaked it a little as I had some compile errors. This code works on the Blue Pill development board (STM32F103C8), which includes a 1.5k pullup resistor on the PA12 (USB_DP) line. Therefore, this code forces the USB_DP line low for a short time, which is like the USB cable has been unplugged and reconnected, thereby forcing the host to re-enumerate the bus when the USB is subsequently configured.
Edit USB_DEVICE/App/usb_device.c and add the code inside the USB_DEVICE_Init_PreTreatment block
void MX_USB_DEVICE_Init(void)
{
/* USER CODE BEGIN USB_DEVICE_Init_PreTreatment */
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_12, GPIO_PIN_RESET);
HAL_Delay(100);
/* USER CODE END USB_DEVICE_Init_PreTreatment */