System resets from code only with active breakpoint - arm

Dear people of stackoverflow,
Beginner here.
I wrote a small piece of code which should reset my MCU (STM32G071RBT6) when a button is pressed and a certain condition is met (see code below).
The button is active low, and an internal pull-up resistor is set active.
The code is set up using STM32CubeIde, using the integrated CubeMX to set up a basic structure and configuration.
// The problematic stuff:
if (HAL_GPIO_ReadPin(BT1_GPIO_Port, BT1_Pin) == 0) {
if (latch == 1) {
latch = 0;
HAL_GPIO_WritePin(LD4_GPIO_Port, LD4_Pin, 0);
} else if (latch == 0) {
__DSB(); // Wait for flash writes to complete!
__disable_irq(); // Disable ALL interrupts (because of a running timer).
NVIC_SystemReset(); // Go for reset!
// NVIC_SystemReset(); can be replaced with:
//SCB->AIRCR = 0x05FA0004;// Write the system reset key and bit.
while(1); // Wait for the hardware to do it's thing...
}
HAL_Delay(500); // Very crude debounce, for now.
}
When I run this, compiled either as debug or as release, the first button press works. I.e. the latch is set to 0 and the output is set low. Then on the second button press the MCU never resets, unless I set a breakpoint anywhere in my program.
To summarize my problem:
The curious thing is this code works perfect, IF a breakpoint is set anywhere in my code (also outside of this specific routine). When, however, there isn't any breakpoint set the MCU does not reset. This I do not understand.
This code is currently running on a NUCLEO-G071RB, on which I've tested all sorts of things before without a problem.
I've tried several things:
Set breakpoints to see if the code is actually running properly (the rest at least) and to see how far I can get to the system reset.
Read the registers of the GPIO input to see if there really is a signal present. There is.
Try different build settings, i.e. debug and release, this makes no difference.
EDIT:
A very curious thing happend:
I rewrote the code, and it works!
// The problematic stuff:
if (HAL_GPIO_ReadPin(BT1_GPIO_Port, BT1_Pin) == 0 && latch ==1) {
latch = 0;
HAL_GPIO_WritePin(LD4_GPIO_Port, LD4_Pin, 1);
HAL_Delay(500); // Very crude debounce, for now.
}
if (HAL_GPIO_ReadPin(BT1_GPIO_Port, BT1_Pin) == 0 && latch == 0) {
__DSB(); // Wait for flash writes to complete!
__disable_irq(); // Disable ALL interrupts.
NVIC_SystemReset(); // Go for reset!
while(1); // Wait for the hardware to do it's thing...
HAL_Delay(500); // Very crude debounce, for now.
}
I shall read up on the actual functionality of the else if () statement. Possibly my understanding is wrong.

Related

How to implement twice button interrupt PIC

I'm working with a 16F1703 PIC mcu, and I want to begin a 7segment lcd cycle (0-9) loop at a touch of a button(A1), after that if I touch the button(A1) twice, I want the Pic to enter in sleep mode.
To do that, I implemented this:
#include <test_interrupt.h>
byte const DataExit[10]={0b01000100,
0b01011111,
0b01100010,
0b01001010,
0b01011001,
0b11001000,
0b11000000,
0b01011110,
0b01000000,
0b01001000};
byte const bitMask[8]={1,2,4,8,16,32,64,128};
//show seven numbers
void segmentCycle(void){
int i, j;
for(i=0;i<10;i++){
for (j=0; j<8;j++){
output_low(CLK);
output_bit(DATA,DataExit[i] & bitMask[j]);
output_high(CLK);
}
delay_ms(7000);
output_low(CLR);
delay_ms(6000);
output_high(CLR);
}
}
#INT_IOC
void IOC_isr(void)
{
segmentCycle();
sleep();
}
void main()
{
port_a_pullups(0x02);
enable_interrupts(INT_IOC_A1);
enable_interrupts(INT_IOC_A1_H2L);
enable_interrupts(GLOBAL);
while(TRUE);
}
For now, if I touch the button, sometimes it starts, otherwise It don't.
What do you suggest?
I'm using ccs compiler.
Your code lacks a proper debounce algorithm and your circuit design is probably flawed. Hooking a button to an interrupt is a waste of a valuable resource, especially if it lacks a debounce circuit. That aside for now, your ISR is going off and doing at least 13000ms of work (well "delay")! ISR's should be short and fast. When they happen, they interrupt whatever code is running at the time, and in the absence of any hard/soft debounce mechanisms, are likely to fire many times per button press (put a scope on that button). That means you're ISR routine might be entered many times before it ever exits from the first call, but even that depends on pin configurations we can only guess at because the relevent code is missing from your OP.
Normally, you'd have a main loop that does whatever work needs to happen and the ISR's simply signal state changes via flags, counters or enumerations. When the main loop detects a state change, it calls whatever function(s) handle that change. In your case, it probably needs to check the current time and the last time the button was pressed, and verify that a minimum period has elapsed (500ms is usually good enough on pin with reasonable pull-up). If not enough time has passed, it resets the flag, otherwise it does the needed work.
See page 72 of the device spec. and take note that there are multiple interrupt sources and the ISR is responsible for determining which source caused it to fire. Your code doesn't look at the interrupt flags, nor does it clear the previous interrupt before exit, so you're never going to see more than one interrupt from any particular source.
With a little bit of searching, you should be able to find free code written to work on your specific PIC chip that handles button debounce. I recommend that you find and study that code. It will make for a very good starting point for you to learn and evolve your project from.
Looks like your hangup is that you want the PIC to be sleeping until the button is pressed. I would do something like this, using CCS C Compiler:
#include <16f1703.h>
#use delay(int=8MHz)
#use fast_io(A)
#include <stdbool.h>
#include <stdint.h>
bool g_isr_ioc_flag = 0;
uint8_t g_isr_ioc_porta = 0;
#int_ioc
void isr_ioc(void)
{
if (!g_isr_ioc_flag) //only trap first IOC
{
g_isr_ioc_flag = 1;
g_isr_ioc_porta = input_a();
}
}
void main(void)
{
uint8_t debounced_a;
set_tris_a(2);
port_a_pullups(0x02);
enable_interrupts(INT_IOC_A1);
enable_interrupts(INT_IOC_A1_H2L);
enable_interrupts(GLOBAL);
for(;;)
{
sleep();
if (g_isr_ioc_flag)
{
// cheap debounce. bit in debounced_a set if pin has been low
// for at least 72ms.
delay_ms(72);
debounced_a = ~g_isr_ioc_porta & ~input_a();
g_isr_ioc_flag = 0;
input_a(); // clear IOC flags left by race condition
if (bit_test(debounced_a, 1))
{
// TODO: user code - handle RA1 press
}
}
}
}
Normally a debounce routine would have had to poll the pin to see if it went low to start debounce timing - but in your case the interrupt on change (IOC) ISR does some of that work for us.
The CCS function input_a() automatically clears the relevant IOC flag bits in IOCAF. That means calling input_a() will clear the ISR flag until the next change.
This design lets you handle other wakeup sources in the main loop. Be aware that any other peripheral ISR or the WDT will wakeup the PIC.

Microcontroller Programming - Program not exiting for loop

I have a simple PIC16F18877 circuit setup on my breadboard and I've successfully gotten an LED to blink within an infinite while loop. I attempted to put the same code inside a for loop that should only execute 5 times, but the LED keeps blinking.
My Code (MPLAB with XC8 Compiler):
#include <xc.h>
#define _XTAL_FREQ 8000000
int main()
{
TRISD1 = 0;
for (int i = 0; i < 5; i++)
{
RD1 = 1;
__delay_ms(500);
RD1 = 0;
__delay_ms(500);
}
return 0;
}
Where do you expect the CPU to jump on return from main? Or rather, what do you expect it to do when you don't tell it what to do? On a desktop computer, the program would normally return to the OS - On an embedded system, there is none.
Most probably, the return from main returns to the startup code and, eventually (either "by accident" or deliberately) to the reset vector, starting your program from the beginning.
If you want the MCU to "stop" actually, "do nothing" you need to force it into an infinite loop instead of return. This is, however, not a common approach on an MCU.
I tried adding a while loop after the for loop and something strange occurred. It appeared to be executing the for and while loop simultaneously. The light would blink link normal and then blink really fast, almost like a stutter and then blink normally, etc.. but it never stopped blinking
Check the watchdog timer. If it's set, the mcu will just reset after a set amount of clock cycles and run the code again and again. You can use CLRWDT() to reset the watchdog timer or just turn the WDT off.
I highly recommend to go through these steps in order to be sure that the mcu does as expected:
Check the PIC configuration bits, are they setup properly? See the documentation in the microchip program folder /docs/chips
Make sure the oscillator is setup correctly.
Read the datasheet and make sure the ports are set correctly, especially the analogue ports using the analogue selection registers.
(my reputation isn't high enough to comment, sorry about that.)
you are not on an operating system here, can you show us the disassembly to show the call to main and what it returns to? Or what if you put an infinite loop before main ends (while(1) continue;) do you get 5 blinks then?

breakpoint inside interrupt C

I'm using LCDK C6748 of Texas Intruments with Code Composer Studio and TMDSEMU100V2U-14T - XDS100v2 USB JTAG Emulator.
LCDK comes with bunch of support functions, including a function that initialize the board and defines which callback functions are called for each interrupt.
I just implemented the callback function, so it does something whenever a new sample comes from the ADC.
I tried to set a breakpoint inside the interrupt but in run time the program "flow" didn't get there.
Furthermore, I've done something simpler:
volatile int flag = 0;
interrupt void interrupt4(void) // interrupt service routine
{
flag = 1;
return;
}
int main(){
// board initializing function, defining sampling rate etc.
L138_initialise_intr(FS_48000_HZ,ADC_GAIN_0DB,DAC_ATTEN_0DB);
while(1){
if (flag == 1){
printf("interrupt entered");
flag = 0;
}
}
}
but the from some reason the while loop was entered only once.
it surprised me because if I don't set breakpoint the interrupt is entered continuously-
I tried to just pass the samples to the speakers line without doing anything else and I heard music.
I have a feeling that I'm missing something very basic about interrupts, I'm quite new to this subject.
Can someone please explain to me [or link me to good source that explain how the mechnism works in DSP]:
1) why we can't set a breakpoint inside interrupt?
2) why even if I set breakpoint in the main, it seems the interrupt doesn't occur, and if I don't it does.
3) which ways I have to have access to the variables in run time, in CCS?
thanks
Try putting breakpoint and then run. see if it hits atleast once. If it does, then your interrupt source is not cleared automatically [because you are not doing so explicitly inside ISR]. in TI controller they expect you to clear ISR path to receive next as per my experience,.
If you dont receive even 1st time interrupt then, check assembly generated for ISR and optimization done by compiler.
Although, you might need to see the timing and global variable protection later, in case of conflicts but as of now above 2 suggestions shall do.
I think that your interrupt is a Timer Interrupt. In many cases jtag, when a breakpoint is triggered, stops a lot of MPU/DSP modules, but timer continue running. This causes overflow of timer, that means that overflow flag is set and the interrupt will be never called until the flag is reset.
I don't know if you can set jtag to stop timers also when a breakpoint is triggered. With freescale MPUs, IAR IDE and segger jtag I can.

Embedded: C Coding for Ctrl-C interrupt in u-boot terminal

I'm a beginner in embedded programming. I'm working on craneboard (ARM Cortex A8). The source code is available at github.
I have created a C code to make an external LED connected via GPIO, to blink. It can be executed in the u-boot console as a command. Currently,
I can't stop the blinking of LED by Ctrl-C. Where does the coding for Ctrl-C interrupt reside?
ret=set_mmc_mux();
if(ret<0)
printf("\n\nLED failed to glow!\n\n");
else{
if(!omap_request_gpio(lpin))
{
omap_set_gpio_direction(lpin,0);
for(i=1;i<21;i++)
{
ctr=0;
if((i%2)==0)
{
num=num-1;
omap_set_gpio_dataout(lpin,num);
}
else
{
num=num+1;
omap_set_gpio_dataout(lpin,num);
}
udelay(3000000);
}
}
}
Kindly guide me.
Try the uboot ctrlc function:
if(ctrlc())
return 1; // or whatever else you want to do
You are working at a low level, so the methods you need to use are also low-level:
Check the UART "data-available" flag within your loop - this is very hardware dependent, but usually involves reading a register, masking some bits off and seeing if the right bit is set.
if data is available, check to see if it is a CTRL-C (0x03) character, exit if so, discard if not
Having now seen nneonneo's answer, I assume that's what the ctrlc() function does...

Struggling to implement tickless support for FreeRTOS on an xmega256a3

I'm struggling to get tickless support working for our xmega256a3 port of FreeRTOS. Looking around, trying to understand under the hood better, I was surprised to see the following line in vTaskStepTick():
configASSERT( xTicksToJump <= xNextTaskUnblockTime );
I don't have configASSERT turned on, but I would think that if I did, that would be raising issues regularly. xTicksToJump is a delta time, but xNextTaskUnblockTime, if I read the code correctly, is an absolute tick time? Did I get that wrong?
My sleep function, patterned after the documentation example looks like this:
static uint16_t TickPeriod;
void sleepXmega(portTickType expectedIdleTime)
{
TickPeriod = RTC.PER; // note the period being used for ticking on the RTC so we can restore it when we wake up
cli(); // no interrupts while we put ourselves to bed
SLEEP_CTRL = SLEEP_SMODE_PSAVE_gc | SLEEP_SEN_bm; // enable sleepability
setRTCforSleep(); // reconfigure the RTC for sleeping
while (RTC.STATUS & RTC_SYNCBUSY_bm);
RTC.COMP = expectedIdleTime - 4; // set the RTC.COMP to be a little shorter than our idle time, seems to be about a 4 tick overhead
while (RTC.STATUS & RTC_SYNCBUSY_bm);
sei(); // need the interrupt to wake us
cpu_sleep(); // lights out
cli(); // disable interrupts while we rub the sleep out of our eyes
while (RTC.STATUS & RTC_SYNCBUSY_bm);
SLEEP.CTRL &= (~SLEEP_SEN_bm); // Disable Sleep
vTaskStepTick(RTC.CNT); // note how long we were really asleep for
setRTCforTick(TickPeriod); // repurpose RTC back to its original use for ISR tick generation
sei(); // back to our normal interruptable self
}
If anyone sees an obvious problem there, I would love to hear it. The behavior it demonstrates is kind of interesting. For testing, I'm running a simple task loop that delays 2000ms, and then simply toggles a pin I can watch on my scope. Adding some printf's to my function there, it will do the first one correctly, but after I exit it, it immediately reenters, but with a near 65535 value. Which it dutifully waits out, and then gets the next one correct again, and then wrong (long) again, alternating back and forth.

Resources