Microcontroller Programming - Program not exiting for loop - c

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?

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.

C Kernel - interrupts not working during while loops

I am making a kernel from scratch in c (Not linux. COMPLETELY from scratch) and I have come along a bit of a problem. I have this code:
#include "timer.h"
int ms = 0;
void timer_handler(struct regs *r){
ms++;
println("I print every tick");
}
void sleep(int ticks){
unsigned long eticks;
eticks = ms + ticks;
while(ms < eticks);
}
And timer_handler is attached to IRQ0 (The PIT) and works perfectly fine. The println that says "I print every tick" works just fine, and If I print the ms variable in my code, it prints the correct amount. But, If I call the sleep function, the timer_handler stops firing and it gets stuck in an infinite loop. Is there any way I can allow interrupts to fire while in a while loop?
REST OF CODE: https://github.com/Codepixl/CodeOS
It sounds like you are not sending the end of interrupt. You need to do an outb(0x20,0x20) (port and data value are the same so it doesn't matter how you have defined outb) for IRQ0 in your interrupt handler. If you are getting only one interrupt, from your question it is not clear if you are getting any interrupts or not, then this is most likely your problem. If not post all the relevant code, e.g. where you are setting up your IDT.
If this is not the case one simple thing you can do to debug is to cause a software interrupt via the int instruction for the corresponding IDT. If that works then it has something to do with the PIC or PIT and not your IDT entry.
Also as others have mentioned you should make ms volatile or use a barrier so the compiler doesn't optimize reading the value. I don't think this is your problem though as you would still be seeing multiple prints if the timer interrupt was occurring.
It was just virtualbox for some reason, it works on my actual PC.

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.

PIC32 WDT reset not working on some PIC32

I have a PIC32 reset function:
void reset_cpu(void)
{
WDTCON=0x8000;
EnableWDT(); // enable the WDT
ClearWDT();
while(1){};
}
It works on a PIC32MX360F512L but not on a PIC32MX695F512L. It just spins forever. Can anyone tell me why, or suggest another way to reset my processor?
If you are using plib.h, you can simply call this function:
void reset_cpu(void)
{
SoftReset();
while(1){};
}
This has the advantage to trigger an instant reset. From reset.h:
How it works: The following steps are performed by this function:
Step 1 - Execute "unlock" sequence to access the RSWRST register.
Step 2 - Write a '1' to RSWRST.SWRST bit to arm the software reset.
Step 3 - A Read of the RSWRST register must follow the write. This action triggers the software reset, which should occur on the next
clock cycle.
Bear in mind plib is obsolete and will soon be removed from MPLAB XC32. Worth considering Harmony for new designs: http://www.microchip.com/mplabharmony
Nothing immediately stands out to me when looking at the datasheets for both of the microcontrollers. However, I do have a couple of suggestions.
First, in your function you are doing the following:
WDTCON=0x8000;
EnableWDT();
If you look at plib.h you will see that it refers to wdt.h. In wdt.h you can see that EnableWDT() is simply a macro that expands to the following:
WDTCONSET = _WDTCON_WDTCLR_MASK
Where the mask is 0x00008000. Basically, you are performing the same operation twice. Just let the macro take care of enabling it.
Also, since you are using the watchdog to reset your device, there is no need to clear the watchdog. ClearWDT() just resets the watchdog and makes your while(1) loop run longer. So, I would write your function like this:
void reset_cpu(void)
{
EnableWDT();
while(1){};
}
Finally, I would recommend taking a look to ensure that you have the correct processor selected in your IDE. I am not certain that this would cause your problem, but if you had the PIC32MX360F512L selected and tried running it on the PIC32MX695F512L, you could end up with the wrong register definitions (assuming that you are using #include "xc.h").
I would also check on how you are setting your device configuration bits. It is possible to set a very long timeout on the watchdog.

STM32F0Discovery TIM1_CC_IRQHandler issue

I am currently trying to debug my project and am having a small issue. We are running the debugger using Ride7 with an RLink connected to our board on the SWD pins. When we run the code we get stuck at one point where the device gets stuck at one point. We paused it and found that the program counter is point to TIM1_CC_IRQHandler. We interpreted this as a flag for timer1's capture compare. However, we are not even using capture compare mode. We never even initialize timer 1. What is the microcontroller trying to do and how can we get past it?
We have tried stepping through the program and cannot follow the PC to the point where it gets stuck. We have run it, it passes through our main while loop, but on the second pass it gets lost. We then reset it and found that the PC is pointing to RESET_HANDLER. This happens in the printf() call; I don't know what it is trying to do.
Code if it helps:
#include <stdio.h>
#include "device_initialization.h"
void main(void)
{
uint32_t time = 0;
//initTIM();
//initADC();
USART_Config();
initGPIO();
while(1)
{
time++;
printf("\n\rUSART Printf Example: retarget the C library printf function to the USART\n\r");
/* Loop until the end of transmission */
/* The software must wait until TC=1. The TC flag remains cleared during all data
transfers and it is set by hardware at the last frame’s end of transmission*/
while (USART_GetFlagStatus(EVAL_COM1, USART_FLAG_TC) == RESET)
{
}
while(time<1000000)
{
time++;
}
}
}
Using printf() in microcontroller is new for me. I think you should get a compile or a linker error. I see a commented row //initTIM(); so I recommend to checking timer init methods (NVIC structure settings).
The delay while cycle runs only at once.

Resources