How to switch from output or input Mode in Stm MIctrocontroller
for exemple after using GpioA_Pin0 as digital output
and in the same programm
how to use it to send data via Usart2
so my problem is how to switch between output and alternative function mode
How to switch from output or input Mode in Stm MIctrocontroller
for exemple after using GpioA_Pin0 as digital output
and in the same programm
how to use it to send data via Usart2
so my problem is how to switch between output and alternative function mode
In general this is a more advanced usage the IO pins but not impossible. Stm uses the hal abstraction. But your both use cases are organized in different files.
You can use Stm32CubeMx to help to generate the init files.
The key would be to switch in the GPIO matrix. Your application needs to handle to GPIO matrix switches.
Port Init for Output:
/* Configure Port */
GPIO_InitStructure.Pin = GPIO_PIN_12;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
GPIO_InitStruct.Alternate = GPIO_NO_ALT;
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
Port Init for UART:
GPIO_InitStruct.Pin = GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF7_USART2;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
So your solution should be to switch between
(GPIO_MODE_OUTPUT_PP) vs (GPIO_MODE_AF_PP + GPIO_AF7_USART2 )
If helpful please vote me up.
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 am having some trouble trying to SET or RESET one of my GPIO pins on the STM32F030.
I'm using the STM32F0xx_HAL_Driver and I initialize GPIO PA12 like this:
GPIO_InitStruct.Pin = GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
I also set my UART using the folowing code:
huart1.Instance = USART1;
huart1.Init.BaudRate = 9600;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_ENABLE;
huart1.gState = HAL_UART_STATE_RESET;
huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
HAL_UART_Init(&huart1);
I know PA12 can be used as UART1_RTS pin but I'm not setting the hardware-flow-control to use RTS or CTS.
The problem I'm facing:
After code initialization I can receive messages over the UART1 connection.
To reply I need to set a pin of an external IC which I'm trying to set using PA12.
But when I call:
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_12, GPIO_PIN_SET);
nothing happens..
Also calling the GPIO_PIN_RESET won't do anything..
What am I missing here??
I've checked (and measured) the PCB, PA12 is only connected to 0V with a 10k pull-down resistor, the external IC isn't pulling the PA12 output low.
Many thanks in advance!
edit:
As requested in the comments, my UART pin configuration:
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF1_USART1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
I'm using DMA to set the Rx:
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
/* DMA interrupt init */
/* DMA1_Channel2_3_IRQn interrupt configuration */
hdma_usart1_rx.Instance = DMA1_Channel3;
hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_usart1_rx.Init.Mode = DMA_NORMAL;
hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart1_rx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
HAL_DMA_Init(&hdma_usart1_rx);
HAL_NVIC_SetPriority(DMA1_Channel2_3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);
2nd EDIT!:
I just found that re-initializing the GPIO PA12 after the UART initialization works!
I can now toggle PA12 without any problems..
But this is not the way it should be!
I'm looking into the STM32 HAL-lib but can't find the piece of code that sets PA12...
Did you enable the GPIOA Clock?
__HAL_RCC_GPIOA_CLK_ENABLE();
Edit:
Please have a look at your void HAL_UART_MspInit(UART_HandleTypeDef *huart) function to see which and how the pins for the usart are configured.
I haven't found the clean solution I really wanted..
But initializing this single pin after the UART initialization seems to do the trick..
PA12 is being set in the UART initialization but I was not able to find the piece of code doing so anywhere
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.
I'm trying to interface a 4-wire resistive touchscreen to a STM32F429 Discovery board but I can't figure out how it works. I want the MCU to detect a touch so I configured the 4 pins like this:
X+ --> input w/pullup connected to EXTI external interrupt
X- --> input floating (tristated)
Y+ --> input floating (tristated)
Y- --> output to GND
in this configuration I should be able to detect a touch and trigger an interrupt on the EXTI line so I can enter a ISR and sample the x and y values with the ADC. But when I connect the X- pin the X+ pin goes to near GND. It seems like current flows between X+ and X- (so the X- is not tristated?).
Here's the code I use to configure the GPIO pins:
GPIO_InitTypeDef gpio;
gpio.Pin = GPIO_PIN_2 | GPIO_PIN_1;
gpio.Mode = GPIO_MODE_INPUT;
gpio.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &gpio);
gpio.Pin = GPIO_PIN_0;
gpio.Mode = GPIO_MODE_INPUT;
gpio.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA, &gpio);
gpio.Pin = GPIO_PIN_5;
gpio.Mode = GPIO_MODE_OUTPUT_PP;
HAL_GPIO_Init(GPIOA, &gpio);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
/* initialization using registers, works the same as above */
// /* Xr and Yu open (input floating) */
// GPIOA->MODER &= ~(GPIO_MODER_MODE2 | GPIO_MODER_MODE1);
// GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPD2 | GPIO_PUPDR_PUPD1);
//
// /* Xl input with pull-up */
// GPIOA->MODER &= ~GPIO_MODER_MODE0;
// GPIOA->PUPDR |= GPIO_PUPDR_PUPD0_0;
//
// /* Yd to GND (output set to 0) */
// GPIOA->MODER |= GPIO_MODER_MODE5_0;
// GPIOA->ODR &= ~GPIO_ODR_OD5;
I can't understand what I am doing wrong or how to configure the tristated pins correctly so they don't pull down the X+ pin.
Between selecting the touch event and reading the touch position, you must reconfigure the pins. The following is from an NXP application note (AN10675), but applies to any microcontroller and can be adapted to STM32:
The outputs are set to provide a voltage source for the analogue measurement of the effective voltage divider formed by the touch position:
On the STM32 it is of course important not to use the GPIO configuration lock feature on these pins as you need three different configurations to read a single touch position event.
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.