FPGA interrupt handling in C - c

I have a coursework for designing a state machine on the Microblaze microprocessor in C. The problem I have is that I have to change a certain picture. Let's say I press BTNL on the FPGA; I have to be presented with a landscape picture for 5 secs and after certain 3 secs I have to make that picture flash. In the meantime, the time 5s -> 0s has to be displayed on the 7-segment display. This is the case where the button has been detected and the flashing mode has to be displayed.
The interrupt occurs every 0.004s
and the microprocessor's clock is 100MHz.
for(j=0; j<=5secs; j++)
{
if(j>3secs)
{
if(counter == sec){
counter=0;
if(temp==white){ //white background
temp=background;
}
else temp=white;
}else counter++;
XGpio_DiscreteWrite(&REGION[4],1,temp);
}
else XGpio_DiscreteWrite(&REGION[4],1,temp);
if(j==5secs)
states = IDLE;
}
My main problem is with displaying the number on the 7-segment display. When I place the displayNumber() function in the case, the whole thing just freezes once it goes to the displayNumber() line. I know the nested for loops cost a lot of time and energy and I think this might cause the problem, but I cannot find a working solution. Any thoughts or advice are really appreciated.
Another thing is that I tried with a flag, but because of the interrupt handling it doesn't work.
EDIT:
I am not trying to get a copy/paste solution of my problem. The whole thing is quite massive, I mean verilog project along with the files for the other functions done in c. I didn't expect you to run the code and reproduce the whole thing, because I had been provided the Verilog project by the school, so you have to generate a bitstream and then upload and run the whole thing on the board. I am here just looking for a suggestion about How would you improved this, have you encountered such behaviour with FPGAs, any ideas.
Thanks for the time spent to read the question!

Thanks to Craig, I did paid more attention on how the displayNumber() func was all set up. So it came out that it stuck in the interrupt and I just had to drive it from other place. So thank you for pointing the right direction, Craig!
If you think this might not be beneficial for anyone else, let me know so I can delete it.
So, the problem was with the definition of the ISR and its combination with the DisplayNumber() func.
Basically, my ISR looked like:
void hwTimerISR(void *CallbackRef)
{
interruptServiced = FALSE;
interruptCounter++;
if (interruptCounter == 1)
{
interruptCounter = 0;
displayDigit(); //needed to display the number on the display
operation(state); // function that moves the FSM's states
interruptServiced = TRUE;
}
return;
}
Basically, the problem was that in the case where I had to cout 5 secs, the displayNumber function would call the displayDigit() and it will all stuck. What I did was to change the states not in the operation function but in the main.

Related

Performance issue with "Dive Into SpriteKit" example code

I made a basic SpriteKit game with my son using step-by-step tutorial from Dive Into SpriteKit book by Paul Hudson.
The game is just one SKScene that draws a ship, a bunch of space junk, and provides basic control. When the game is over, we follow instructions from the book and do:
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
if let scene = GameScene(fileNamed: "GameScene") {
scene.scaleMode = .aspectFill
self.view?.presentScene(scene)
}
}
Unfortunately with each new game scene FPS goes down and after ~20 game overs on my iPad the game is unplayable. I guess something is not properly de-initialized, but I am not sure where to look and how to fix this.
I checked "canonical" implementation form the book and they all have exactly the same issue on iOS 12.
Our complete implementation on GitHub.
I will appreciate advice on how to manage scenes lifecycle to keep performance.
Thank you #0x141E for the solution and the advices!
The issue was with the timer (which is in use to add nodes to the scene). A timer runs in Run Loop and have to be invalidated with:
timer!.invalidate()
Adding the invalidation in GameOver for both timers solved the major performance degradation issue as well as the memory leak.
Following the advice, we learned a bit more about SKAction, and another way of creating space junk on schedule seems to be:
run(SKAction.repeatForever(SKAction.sequence([
SKAction.run(createEnemy),
SKAction.wait(forDuration: 0.45)
])))
In this case we still need to make sure we do stop all the actions in the GameOver.
removeAllActions()

How can I distinguish short from long button press in C?

I wrote a code for determining the push button state wheather it's long pressed or not. By the way this function is called by a timer interrupt routine in every 1 ms.
If you pressed more than 1 second, LongPressed is active ShortPressed is passive .so vice versa.
1- But it seems really dummy how can I make it shorter and more efficient according to both readibilty and professional rules?
BTW I updated the code like below.
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/*button pressed and count*/
if(!HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13))
{
usTick++;
}
/*not pressed*/
else
{
if( usTick > 1000){
ButtonState.PressedState = LongPressed;
HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_5);
usTick = 0;
}
else if( usTick >350){
ButtonState.PressedState = ShortPressed;
HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_5);
usTick = 0;
}
usTick = 0;
}
}
2- What should I add or change to get double Tap pressing information in this updated code?
Almost every STM32 timer has "external trigger synchronization" function. You can read about it in timer functional description in reference manual. You can use "Slave mode: Trigger mode" to start counting on "button down" event. And in EXTI interrupt of "button up event" you can read timer counter and do your business.
I don't know how to implement this via HAL, but Standard Peripheral Library should have the example.
1) Your code is only able to handle 1 button. Make it object oriented to read n buttons.
1 ms is much too fast. 20 ms should work fine. Remember: humans are slow.
2) I once had spent some time creating a LED controller with two pushbutton rotary encoders. These would feature advanced programming methods by means of pushing them long or multiple times. You could use the result of my sparring (it was never completed) as inspiration. The button code is fairly complex, it should fulfill your needs. And I remember it to be functional.
https://github.com/Jeroen6/LED-Rotary-Dimmer-SW/blob/master/user/button.c
https://github.com/Jeroen6/LED-Rotary-Dimmer-SW/blob/master/user/button.h
Forgive me for not having the indentations worked out correctly.

Push a button while reading sensor in Arduino

I've been doing a little thermometer project to learn Arduino and there is an annoying thing that I have no idea how to resolve.
I have two push buttons to set Min and Max temperature and when I push the buttons it's supposed to set the Min and Max temperature on display.
The problem is that sometimes (50% of times) when I push the buttons during the reading of the temperature sensor, the buttons don't work. I press it but the Min/Max temperature are not set because Arduino is stuck in reading the temperature sensor.
Is there any trick to solve this kind of problem? If I had a keyboard for typing some number for example I imagine I would have the same problem and It's not "user-friendly".
Here is an example of part of the code I'm using:
#include <OneWire.h>
#include <DallasTemperature.h>
#include <LiquidCrystal.h>
//variables declaration...
void setup() {
sensors.begin();
sensors.getAddress(sensor1, 0);
pinMode(buzzer, OUTPUT);
pinMode(btBuzzer, INPUT);
pinMode(btMin, INPUT);
pinMode(btMax, INPUT);
}
void loop() {
readButtons();
playBuzzer();
readTemperature();
printDisplay();
delay(150);
}
void readButtons(){
if(digitalRead(btBuzzer)){
buzzerOn = !buzzerOn;
}
if(digitalRead(btMin)){
if(tempMin == 69)
tempMin = 59;
else
tempMin++;
}
if(digitalRead(btMax)){
if(tempMax == 75)
tempMax = 63;
else
tempMax++;
}
}
void readTemperature(){
sensors.requestTemperatures();
temperature = sensors.getTempC(sensor1);
}
//lots of other methods
As others have pointed out here, the button press may not happen at the same time as you query the pin with digitalRead(btBuzzer). This type of problem is what so called "interrupts" were invented for, which allow you to respond to events that may occur while you are not monitoring the pin of interest.
For example, the Arduino UNO R3 allow for interrupts on pin 2 and 3. You should look up the reference for attachInterrupt(). The processor will execute a callback function in the event (the "interrupt") that you register for (e.g. the voltage on pin 2 changing from low to high). This means that you will no longer have to call a readButtons() function from your main loop.
Some of the best ways to learn coding exist in how to answer this question.
What I'd like to suggest doing is to try timing your code. Remember that loop() is creating a repeating structure. So we can say things like how long does the computer take to run each loop. When we have an interrupt like a button press how does that effect the iteration through the loop and is it conditional about how to rest the processor (the delay).
The delay is required so as to not do what's called "spin" the processor (have the processor as quickly as it can do a lot of work to accomplish absolutely nothing). However, notice how the code doesn't account for work done changing how long we delay?
Now let's imagine the processor actually can go through that loop more than one time very quickly. Remember delay of only 150 milliseconds isn't a lot of time. So maybe one button press will be enough to set tempMin from 59 to 69 in rapid succession and loop several times over rather than just increasing one number at a time.
What you have here is a chance to learn debugging. First trick is to determine is the loop running too fast or too slow; are you getting desired functionality or not and finally if you can reask the question after you know if it's happening too fast or slow.
For now, I'd recommend taking a look at global variables and finite state machines (i.e. if you're in a state of button press, don't accept any further button presses until you're done with your state and only transition in known ways).

Running two loops simultaneously for a game - C

I'm making a game in C for my programming class, and I have to place a time countdown on the game, but I can't make it work right, because if a put a countdown function and a delay(1000), it works for the countdown, but doesn't work for the game , because it makes wait the 1s every move.
My code so far is
while(tempo > 0)
{
tempo_na_tela(&tempo);
contador_tempo(&tempo);
if(kbhit())
{
mover_refem(getch(), p_refem, &refem.px, &refem.py,
numero_inimigos_na_tela(n, in1));
}
mover_inimigo(n, p_terrorista, in1);
}
The function tempo_na_tela(..) puts the string of time on the screen, the contador_tempo(..) is the countdown, the mover_refem(...) is the function to move the game character, and the mover_inimigo(..)is a function that randomly moves the enemy in the screen.
I need to place the tempo_na_tela and the contador_tempo functions in one loop, that run simultaneously with the other loop, that run the moving functions.
How can I do it?
You're experimenting a XY problem i think.
You don't need to run simultaneously thoses 2 functions. What you're trying to accomplish is a game loop, it's very common in video-games, especially early ones.
Ask yourself, when do you need to re-paint your elements ? The answer is probably after having updated all of your data (Time, ennemy position, and having logged your player's movement)
So, you don't need simultaneous looping (ie thread i would have suggested, even if it's not true simultaneous, but that's another story.)
Instead, you can stick with one loop, but you have to do something in this fashion :
while (game_not_ended())
{
update_data();
repaint_data();
}
I hope you'll take the time to reconsider your code and the scope of your issue.

Produce tones at certain time-interval using C programming

Im using C language for a PIC18F to produce tones such that each of them plays at certain time-interval. I used PWM to produce a tone. But I don't know how to create the intervals. Here is my attempt.
#pragma code //
void main (void)
{
int i=0;
// set internal oscillator to 1MHz
//OSCCON = 0b10110110; // IRCFx = 101
//OSCTUNEbits.PLLEN = 0; //PLL disabled
TRISDbits.TRISD7 = 0;
T2CON = 0b00000101; //timer2 on
PR2 = 240;
CCPR1L = 0x78;
CCP1CON= 0b01001100;
LATDbits.LATD7=0;
Delay1KTCYx(1000);
while(1);
}
When I'm doing embedded programming, I find it extremely useful to add comments explaining exactly what I'm intending when I'm set configuration registers. That way I don't have to go back to the data sheets to figure out what 0x01001010 does when I'm trying to grok the code the next time I have to change it. (Just be sure to keep the comments in sync with the changes).
From what I can decode, it looks like you've got the PWM registers set up, but no way to change the frequency at your desired intervals. There are a few ways to do it, here are 2 ideas:
You could read a timer on startup, add the desired interval to get a target time, and poll the timer in the while loop. When the timer hits the target, set a new PWM duty cycle, and add the next interval to your target time. This will work fine, until you need to start doing other things in the background loop.
You could set timer0's count to 0xFFFF-interval, and set it to interrupt on rollover. In the ISR, set the new PWM duty cycle, and reset timer0 count to the next interval.
One common way of controlling timing in embedded processes looks like this:
int flag=0;
void main()
{
setup_interrupt(); //schedule interrupt for desired time.
while (1)
{
if (flag)
{
update_something();
flag = 0;
}
}
Where does flag get set? In the interrupt handler:
void InterruptHandler()
{
flag = 1;
acknowledge_interupt_reg = 0;
}
You've got all the pieces in your example, you just need to put them together in the right places. In your case, update_something() would update the PWM. The logic would look like: "If it's on, turn it off; else turn it on. Update the tone (duty cycle) if desired"
There should be no need for additional delays or pauses in the main while loop. The goal is that it just runs over and over again, waiting for something to do. If the program needs to do something else at a different rate, you can add another flag, which is triggered completely independently, and the timing of the two tasks won't interfere with each other.
EDIT:
I'm now confused about what you are trying to accomplish. Do you want a series of pulses of the same tone (on-off-on-off)? Or do you want a series of different notes without pauses (do-re-me-fa-...)? I had been assuming the latter, but now I'm not sure.
After seeing your updated code, I'm not sure exactly how your system is configured, so I'm just going to ask some questions I hope are helpful.
Is the PWM part working? Do you get the initial tone? I'm assuming yes.
Does your hardware have some sort of clock pulse hooked up to the RA4/T0CKI pin? If not, you need T0 to be clock mode, not counter mode.
Is the interrupt being called? You are setting INT0IE, which enables the external interrupt, not the timer interrupt
What interval do you want between tone updates? Right now, you are getting 0xFFFF / (clock_freq/8) You need to set the TMR0H/L registers if you want something different.
What's on LATD7? and why are you clearing it? Are you saying it enables PWM output?
Why the call to Delay()? The timer itself should be providing the needed delay. There seems to be a disconnect about how to do timing. I'll expand my other answer
Where are you trying to change the PWM frequency? Don't you need to write to PR2? You will need to give it a different value for every different tone.
"Halting build on first failure as requested."
This just says you have some syntax error, without showing us the error report, we can't really help.
In Windows you can use the Beep function in kernel32:
[DllImport("kernel32.dll")]
private static extern bool Beep(int frequency, int duration);

Resources