Using Tim2 inside interrupt handler for STM32F1 - embedded

I am blinking LED using TIM2 General timer.
Code in main.c
HAL_TIM_Base_Start_IT(&htim2);
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
if(htim->Instance==TIM2){
HAL_GPIO_TogglePin(GPIOB, LED_Pin);
}
}
When the button is clicked EXTI interrupt should be called to blink the led faster 20 times. However, LED stays on and stops blinking at all.
void EXTI0_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
if(GPIO_Pin == BT_Pin){
for(volatile int i=20; i>0; i--){
HAL_GPIO_TogglePin(GPIOB, LED_Pin);
HAL_Delay(100);
}
}
}
Could you please advice how can i adjust interrupt ISR for EXTI so it will use TIM2 as well with faster blinking.

HAL_GPIO_EXTI_Callback() runs in the interrupt context - it is not appropriate to flash the indicator there much less include a delay. No other code while run while in the interrupt, and HAL_Delay() is probably not interrupt safe in any case.
Instead, in the button handler, set a down-counter to be decremented in the timer handler, and in the timer handler set the reload depending on the down-counter being zero or not. Something like this:
[I have not included the HAL calls to do the TODO's above, because I'd have to look them up, but that is the outline.]
volatile unsigned fast_flash_count = 0 ;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM2)
{
HAL_GPIO_TogglePin(GPIOB, LED_Pin);
if( fast_flash_count > 0 )
{
fast_flash_count-- ;
// Set TIM2 reload to fast-flash period
TODO
}
else
{
// Set TIM2 reload to slow-flash period
TODO
}
}
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == BT_Pin)
{
fast_flash_count = 20 ;
// Set TIM2 counter to current reload value
// to force immediate interrupt
TODO
}
}

Related

Raspberry Pi Pico locks up when I try to use interrupts

I'm trying to use encoders to track the movement of three wheels on a robot, but as soon as any of the motors move the robot "locks up", it stops responding to commands, stops printing to the serial monitor, and just keeps spinning its wheels until I turn it off. I cut out everything except just the code to track one encoder and tried turning the wheel by hand to sus out the problem, but it still locked up. And even more strangely, now it will start spinning one of the wheels even though I've removed any code that should have it do that, even by mistake.
I used the Arduino IDE to program the pico since I've got no familiarity with python, but I can't find any information or troubleshooting tips for using interrupts with the pico that don't assume you're using micropython.
Here's the simplified code I'm using to try to find the problem. All it's meant to do is keep track of how many steps the encoder has made and print that to the serial monitor every second. Ive tried removing the serial and having it light up LEDs instead but that didn't help.
int encA = 10;
int encB = 11;
int count = 0;
int timer = 0;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
attachInterrupt(digitalPinToInterrupt(encA),readEncoder,RISING);
timer = millis();
}
void loop() {
// put your main code here, to run repeatedly:
if (timer - millis() > 5000) {
Serial.println(count);
timer = millis();
}
}
void readEncoder() {
int bVal = digitalRead(encB);
if (bVal == 0) {
count--;
}
else{
count++;
}
}
Does the mapping function digitalPinToInterrupt for the Pi Pico work?
Can you try just using the interrupt number that corresponds to the pi?
attachInterrupt(9,readEncoder,RISING); //Or the number 0-25 which maps to that pin
https://raspberrypi.github.io/pico-sdk-doxygen/group__hardware__irq.html
You have the wrong pin to encoder in your example (maybe you incorrectly copy and pasted)?
attachInterrupt(digitalPinToInterrupt(**encA**),readEncoder,RISING);
void readEncoder() {
int bVal = digitalRead(**encB**); ...}
There is similar code on GitHub that you could modify and try instead.
https://github.com/jumejume1/Arduino/blob/master/ROTARY_ENCODER/ROTARY_ENCODER.ino
It might help you find a solution.
Also,
https://www.arduino.cc/reference/en/libraries/rpi_pico_timerinterrupt/
The interrupt number corresponds to the pin (unless you have reassigned it or disabled it) so for pin 11 the code can be:
attachInterrupt(11, buttonPressed, RISING);
This works:
bool buttonPress = false;
unsigned long buttonTime = 0; // To prevent debounce
void setup() {
Serial.begin(9600);
pinMode(11, INPUT_PULLUP);
attachInterrupt(11, buttonPressed, RISING);
// can be CHANGE or LOW or RISING or FALLING or HIGH
}
void loop() {
if(buttonPress) {
Serial.println(F("Pressed"));
buttonPress= false;
} else {
Serial.println(F("Normal"));
}
delay(250);
}
void buttonPressed() {
//Set timer to work for your loop code time
if (millis() - buttonTime > 250) {
//button press ok
buttonPress= true;
}
buttonTime = millis();
}
See: https://raspberrypi.github.io/pico-sdk-doxygen/group__hardware__irq.html for disable, enable etc.

Transmit complete call back not getting called in UART DMA

What I'm trying to do is fairly simple. Transmit through DMA and wait till it gets transmitted. And then receive and wait till it is received.
When I comment out the receive part(including the call back), it is going into the transmit complete call back function. But when I un-comment the receive portion, it is not going into the tx cplt call back and it is directly going into the receive cplt callback. And when I check the receive buffer I'm not getting what I expected(obviously). What could have gone wrong?
I'm using Atollic True Studio V 9.0 , CubeMx v5.1.0, STM32F407VG-DISC1 board and enabled DMA for UART2.
I've tried sending char buffer through UART DMA and receive it. It seems it is not transmitting at all as it is not going into txCplt call back. And it is directly going into Rxcplt call back.
uint8_t tx_arr[10], rx_arr[10];
__IO ITStatus UartReady = RESET;
int main(void)
{
int i = 0;
for(i = 0; i<10; i++)
rx_arr[i] = 0;
for(i = 0; i<10; i++)
tx_arr[i] = i*2;
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_DMA_Init();
MX_USART6_UART_Init();
MX_USART2_UART_Init();
while (1)
{
if( HAL_UART_Transmit_DMA(&huart2, (uint8_t*)tx_arr, 10)!= HAL_OK )
{
Error_Handler();
}
while(UartReady != SET)
{
}
UartReady = RESET;
if( HAL_UART_Receive_DMA(&huart2, (uint8_t*)rx_arr, 10)!= HAL_OK )
{
Error_Handler();
}
while(UartReady != SET)
{
}
UartReady = RESET;
}
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
UartReady = SET;
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
UartReady = SET;
}
I expect the rx_arr will get filled by 0,2,4,6,...18 but it is getting filled with junk
As this looks to me, the reason is that you are using the same flag variable from both ISRs, both times doing busy waiting in your main loop.
If you uncomment both handler actions, you will sooner or later end up with a race condition where both handlers put their "SET" value quickly one by one - before the main loop waits for it. Then, the main loop "consumes" this flag by setting the variable back to "RESET". A few lines later, the other waiting loop comes and isn't served (because both ISRs ran earlier and only left a single "SET" value, one overwriting the other). Then, your main loop is stuck.
In order to verify my assumption, you can activate a one-sided watchdog before entering into the main loop, and trigger it every main loop cycle. If the main loop gets stuck as I assume, you will detect that the reset cause points to the watchdog afterwards.

Communicating dsPIC with PC application through UART. Receiver interrupt handling

I'm communicating my C# applications with dsPIC x16 microcontroller using UART. I want to send/receive fixed size frames and I tried to manage it in a following way:
if(readFrame)
{ IEC0bits.U1RXIE=0; //turn off the U1RX interrupts
readFrame = false;
while(indexer < 8 )
{
while(!U1STAbits.URXDA);
modbusBuffer[indexer]=U1RXREG;
indexer++;
}
if(indexer == 8)
{
modbusRecvTask(modbusBuffer);
indexer=0;
}
IEC0bits.U1RXIE=1; //turn on U1RX interrupts
}
void _ISR_NAP _U1RXInterrupt()
{
if(IFS0bits.U1RXIF)
{
IFS0bits.U1RXIF = 0; //set the interrupt flag to false
if(U1STAbits.OERR==1) //check overload error
{
U1STAbits.OERR=0; //clear error flag
}
else
{
readFrame = true;
}
}
}
The thing is that it works fine only for the first received frame. After that the program goes into the receiver interrupt again and sets the flag readFrame to true even though no bytes were send and is getting stuck in line:
while(!U1STAbits.URXDA);
I've read some advices to clear the read buffer of the UART in order to prevent the program to go into the ISR again but I couldn't find a way to do it.

How to wake up a process blocked by pause()?

I need to block and wake a process using SIGUSR2 and SIGUSR1 respectively. Below here's my signal handler sub routine. How do I wake a process blocked by pause?
void sig_handler(int sig) {
static int i = 1;
if(sig == SIGUSR2) {
pause();
}
else if(sig == SIGUSR1) {
/* I don't what to write here */
}
}
Also, I read somewhere pause() is not a good programming practice, is there any other means to suspend a process for some time?
See this page
In general, doing a lot of works in signals is ... tricky. Some things are not async-signal-safe, and therefore it makes robust programming there a bit difficult. In your case, pause() waits for a signal to arrive, but since you are calling it from the signal handler, it is not going to work there (I think).
As to making the process sleep and resume on signals. Look at the page I linked above. The best way is to have the signal handlers simply set flags and have the main thread (i.e. in main() or in an event loop) react to these flags. As recommended by the page, use sigsuspend when SIGUSR2 is received to pause the process until SIGURS1 is received.
It's simple. Use the 'kill' system call-
void sig_handler(int sig) {
static int i = 1;
if(sig == SIGUSR2) {
pause();
}
else if(sig == SIGUSR1) {
kill(<pid of process to wake up>, sig);
// make sure that process with pid has registered for sig
}
}

Monitor keyboard events by adding observer in RunLoop

My Run Loop Observer is written as follows:
void observerCallback(CFRunLoopObserverRef observer,
CFRunLoopActivity activity, void* info)
{
println("%u", activity);
}
//-----------------------------
void InstallObserver()
{
CFRunLoopObserverRef myObserver = NULL;
int myActivities = kCFRunLoopEntry;
myObserver = CFRunLoopObserverCreate(NULL, myActivities, YES,
/* repeat */ 0, &observerCallback, NULL);
if (myObserver)
{
CFRunLoopAddObserver(CFRunLoopGetCurrent(), myObserver,
kCFRunLoopCommonModes);
}
}
Every time I press any key in my Application the observerCallback is called 4 times.
The question is:
How can I obtain key code inside observerCallback?
Thanks.
Based on the comments on your question, you want a local event monitor, AKA:
+[NSEvent addLocalMonitorForEventsMatchingMask:handler:]
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSEvent_Class/Reference/Reference.html#//apple_ref/occ/clm/NSEvent/addLocalMonitorForEventsMatchingMask:handler: