stm32 external interrupt pin mode changing - stm32

I am designing an ESC with stm32f103c8t6. In my design I am using BEMF circuitry to detect phase of the motor. From BEMF circuitry (with comparator LM339) I am reading 3 interrupt pins but when code running I need to change the pinmode (like rising edge detection to falling edge detection) and also I need to disable other 2(it depends on phase of the motor at that time) interrupt pins in order to not to read noise that comes from circuitry. How can I do that?
Thanks for your help,

Something like this to switch between falling/rising edge:
void isr_hallsensor(void) {
if (hallsensor_edge_select) {
//rising edge, magnet has left the detection zone.
gpio_hall_sensor.Mode = GPIO_MODE_IT_FALLING;
HW_GPIO_Init(HALLSENSOR_PORT, HALLSENSOR_PIN, &gpio_hall_sensor);
hallsensor_edge_select = 0;
__HAL_GPIO_EXTI_CLEAR_IT(HALLSENSOR_PIN);
} else {
//falling edge, magnet detected.
gpio_hall_sensor.Mode = GPIO_MODE_IT_RISING;
HW_GPIO_Init(HALLSENSOR_PORT, HALLSENSOR_PIN, &gpio_hall_sensor);
hallsensor_edge_select = 1;
__HAL_GPIO_EXTI_CLEAR_IT(HALLSENSOR_PIN);
}
}
Something like this to enable an interrupt:
__HAL_TIM_CLEAR_IT(&htim16, TIM_IT_UPDATE);
HAL_NVIC_SetPriority(TIM1_UP_TIM16_IRQn, 15, 15);
HAL_NVIC_EnableIRQ(TIM1_UP_TIM16_IRQn);
Something like this to disable an interrupt:
HAL_NVIC_DisableIRQ(TIM6_DAC_IRQn);
This will at least get you started, this is for STM32L4.

Related

STM32L4A6 - ISR is processed twice

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!

How to make LED blink at second press on push button?

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.

How to properly use movement components in unreal engine 4?

I'm trying to set up a very simple RTS-like camera that moves around at the pressure of wasd or the arrow keys. But I can't manage to make it work.
I have a player controller that handles input like so:
void AMyPlayerController::SetupInputComponent()
{
Super::SetupInputComponent();
InputComponent->BindAxis("CameraForward", this, &AMyPlayerController::CameraForward);
}
void AMyPlayerController::CameraForward(float Amount)
{
MyRtsCameraReference->CameraForward(Amount);
}
In my camera actor, which inherits from APawn, and I initialize like this:
ARtsCamera::ARtsCamera()
{
PrimaryActorTick.bCanEverTick = true;
CameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("CameraComponent"));
SpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArm"));
// I tried to use a static mesh in place of this but nothing changes.
SceneRoot = CreateDefaultSubobject<USceneComponent>(TEXT("SceneRoot"));
MovementComponent = CreateDefaultSubobject<UFloatingPawnMovement>(TEXT("MovementComponent"));
SpringArm->TargetArmLength = 500.f;
SetRootComponent(SceneRoot);
SpringArm->SetupAttachment(SceneRoot);
CameraComponent->SetupAttachment(SpringArm);
SpringArm->AddLocalRotation(FRotator(0.f, -50.f, 0.f));
}
I try to handle the movement like this:
void ARtsCamera::CameraForward(float Amount)
{
if (Amount != 0)
{
// Here speed is a float used to control the actual speed of this movement.
// If Amount is printed here, I get the correct value of 1/-1 at the pressure of w/s.
MovementComponent->AddInputVector(GetActorForwardVector() * Amount * Speed);
}
}
In my set up i then create a blueprint which inherits from this to expose to the level design phase a few parameters like Speed or the spring arm length and so on, but this shouldn't be the issue as if I use the C++ class the behaviour is the same.
The following works as expected (except for the fact that when i then rotate the camera, vectors get messed up) but i would like to use a movement component.
void ARtsCamera::CameraForward(float Amount)
{
if (Amount != 0)
{
AddActorWorldOffset(GetActorForwardVector() * Amount * CameraMovingSpeed);
}
}
The mobility is set to movable. And so far everything seems to be simple enough, no compile errors, but the actor doesn't move. What am I missing?
Also would you use the FloatingPawnMovement for this or would you go for another movement component?
Thanks in advance.

How to use the RTC clock with the STM32 using HSE with PLL

I am using the stm32F0xx series and am trying to get the RTC to work. I have an external 8MHz crystal connected and using PLL to create a sysclk of 48MHz. Obviously I would like to use this clock with the RTC. I have tried the following:
//(1) Write access for RTC registers
//(2) Enable init phase
//(3) Wait until it is allow to modify RTC register values
//(4) set prescaler,
//(5) New time in TR
//(6) Disable init phase
//(7) Disable write access for RTC registers
RTC->WPR = 0xCA; //(1)
RTC->WPR = 0x53; //(1)
RTC->ISR |= RTC_ISR_INIT; //(2)
while ((RTC->ISR & RTC_ISR_INITF) != RTC_ISR_INITF) //(3)
{
//add time out here for a robust application
}
RCC->BDCR = RCC_BDCR_RTCSEL_HSE;
RTC->PRER = 0x007C2E7C; //(4)
RTC->TR = RTC_TR_PM | 0x00000001; //(5)
RTC->ISR &=~ RTC_ISR_INIT; //(6)
RTC->WPR = 0xFE; //(7)
RTC->WPR = 0x64; //(7)
In the main loop there is an infinite for that turns two led's on and off. Without the RTC config this works fine but as soon as I add in the code above it stops working.
If I do this then the rest of the code breaks. Can I use HSE and if so am I using the prescalar correctly?
This example from actual working code for using HSE for RTC at STM32f429. It uses STM HAL software library, but can gives you a clue to solve.
Please note, that HSE already must be configured and used as frequency source before this code.
Remark: when reading, you should read not just time but also date.
i.e.:
HAL_RTC_GetTime(&RTChandle, &RTCtime, FORMAT_BIN); //first
HAL_RTC_GetDate(&RTChandle, &RTCdate, FORMAT_BIN); //second, even if you dont required
otherwise registers stay frozen (in this case you see ticks only under debugger but not in real run, because debug reads both registers)
// enable access to rtc register
HAL_PWR_EnableBkUpAccess();
// 1. 8Mhz oscillator (Source crystal! Not after PLL!) div by 8 = 1 Mhz
__HAL_RCC_RTC_CONFIG(RCC_RTCCLKSOURCE_HSE_DIV8);
RTChandle.Instance = RTC;
RTChandle.Init.HourFormat = RTC_HOURFORMAT_24;
// 2. (1 Mhz / 125) = 7999 ticks per second
RTChandle.Init.AsynchPrediv = 125 - 1;
RTChandle.Init.SynchPrediv = 8000 - 1;
RTChandle.Init.OutPut = RTC_OUTPUT_DISABLE;
RTChandle.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
RTChandle.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
// do init
HAL_RTC_Init(&RTChandle);
// enable hardware
__HAL_RCC_RTC_ENABLE();

mbed not sleep with RTOS

I want to create a low power application with mbed (LPC1768) and have been following tutorial by Jim Hamblen at: https://mbed.org/cookbook/Power-Management and also http://mbed.org/users/no2chem/notebook/mbed-power-controlconsumption/
I was able to wake the mbed from Sleep() by GPIO interrupt, UART interrupt, and Ticker. I use PowerControl library.
Here is my code:
#include "mbed.h"
#include "PowerControl/PowerControl.h"
#include "PowerControl/EthernetPowerControl.h"
// Need PowerControl *.h files from this URL
// http://mbed.org/users/no2chem/notebook/mbed-power-controlconsumption/
// Function to power down magic USB interface chip with new firmware
#define USR_POWERDOWN (0x104)
int semihost_powerdown() {
uint32_t arg;
return __semihost(USR_POWERDOWN, &arg);
}
DigitalOut myled1(LED1);
DigitalOut myled2(LED2);
DigitalOut myled3(LED3);
DigitalOut myled4(LED4);
bool rx_uart_irq = false;
Serial device(p28, p27); // tx, rx
InterruptIn button(p5);
// Circular buffers for serial TX and RX data - used by interrupt routines
const int buffer_size = 255;
// might need to increase buffer size for high baud rates
char tx_buffer[buffer_size];
char rx_buffer[buffer_size];
// Circular buffer pointers
// volatile makes read-modify-write atomic
volatile int tx_in=0;
volatile int tx_out=0;
volatile int rx_in=0;
volatile int rx_out=0;
// Line buffers for sprintf and sscanf
char tx_line[80];
char rx_line[80];
void Rx_interrupt();
void blink() {
myled2 = !myled2;
}
int main() {
//int result;
device.baud(9600);
device.attach(&Rx_interrupt, Serial::RxIrq);
// Normal mbed power level for this setup is around 690mW
// assuming 5V used on Vin pin
// If you don't need networking...
// Power down Ethernet interface - saves around 175mW
// Also need to unplug network cable - just a cable sucks power
PHY_PowerDown();
myled2 = 0;
// If you don't need the PC host USB interface....
// Power down magic USB interface chip - saves around 150mW
// Needs new firmware (URL below) and USB cable not connected
// http://mbed.org/users/simon/notebook/interface-powerdown/
// Supply power to mbed using Vin pin
//result = semihost_powerdown();
// Power consumption is now around half
// Turn off clock enables on unused I/O Peripherals (UARTs, Timers, PWM, SPI, CAN, I2C, A/D...)
// To save just a tiny bit more power - most are already off by default in this short code example
// See PowerControl.h for I/O device bit assignments
// Don't turn off GPIO - it is needed to blink the LEDs
Peripheral_PowerDown( ~( LPC1768_PCONP_PCUART0 |
LPC1768_PCONP_PCUART2 |
0));
// use Ticker interrupt and Sleep instead of a wait for time delay - saves up to 70mW
// Sleep halts and waits for an interrupt instead of executing instructions
// power is saved by not constantly fetching and decoding instructions
// Exact power level reduction depends on the amount of time spent in Sleep mode
//blinker.attach(&blink, 0.05);
//button.rise(&blink);
while (1) {
myled1 = 0;
printf("bye\n");
Sleep();
if(rx_uart_irq == true) {
printf("wake from uart irq\n");
}
myled1 = 1;
}
}
// Interupt Routine to read in data from serial port
void Rx_interrupt() {
myled2 = !myled2;
rx_uart_irq = true;
uint32_t IRR0= LPC_UART2->IIR;
while ((device.readable()) && (((rx_in + 1) % buffer_size) != rx_out)) {
rx_buffer[rx_in] = LPC_UART2->RBR;
rx_in = (rx_in + 1) % buffer_size;
}
}
Here is the problem: The Sleep() doesn't put the mbed to sleep when mbed-rtos library is added. Even when I don't use any function calls from the rtos library , Sleep() doesn't work.
My explanation: Probably the rtos has a timer running in the background and it generates an interrupt every now and then. (But it kinda doesn't make sense because I haven't use any function or object from rtos library)
My question:
Has any one made the Sleep() function work with rtos? if yes, please point me to the right direction or if you have the solution, please share.
I'm not sure if the Sleep() function is designed for RTOS use, but I doubt it. Someone with better knowledge in mbed-rtos could probably tell for sure, but I suspect that IRQ handling in the RTOS could cause the problem. If Sleep() relies on WFE then the MCU will sleep if there is no pending interrupt flag. In a super loop design you (should) have full control over this; with an RTOS you don't.
I suggest using Thread::wait() instead, which should have full knowledge about what the RTOS does. Can't tell if it causes a sleep, but I expect no less.
I used the following library once and it worked flawlessly. I am not sure if it would work with mbed 5 but its worth a try.
https://os.mbed.com/users/no2chem/code/PowerControl/