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

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...

Related

System resets from code only with active breakpoint

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.

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.

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.

How can I send a string serially from an 8051 only ONCE?

I am making an 8051 microcontroller communicate wirelessly with a computer. The microcontroller will send a string to its serial port (DB9) and the computer will receive this string and manipulate it.
My problem is that I do not know how to make the 8051 transmit the string just once. Since I need to manipulate the string at the PC end it has to be received only one time. Currently, even though in the C code I am sending the string once, on my computer I am receiving the same string continuously.
I assume this is because whatever is in the SBUF is continuously transmitted. Is there any way that I can send my string only once? Is there a way to empty the SBUF?
I tried to use the RTS (Request to Send) pin (7th pin) on the DB9 because I read somewhere that if I negated the voltage on that pin it would stop the flow of data to the serial port. So what I did was programmed my microcontroller to send the string and then sent logic level 0 to an output pin that was connected to my DB9 RTS pin. However, that didn't work.
Does anyone have any suggestions? I'd really appreciate them.
EDIT
The software that I'm using on the PC is X-CTU for Xbee modules. This is the code on my microcontroller:
include reg51.h
void SerTx(unsigned char);
void main(void)
{
TMOD = 0x20;
TH1 = 0xFD;
SCON = 0x50;
TR1 = 1;
SerTx('O');
SerTx('N');
SerTx('L');
SerTx('Y');
}
void SerTx(unsigned char x)
{
SBUF = x;
while(TI==0);
TI = 0;
}
Could someone please verify that it is in fact only sending the string once?
EDIT
Looks like Steve, brookesmoses and Neil hit the nail on the head when they said that it was what was happening AFTER my main function that was causing the problem. I just tried the suggested code Steve put up (more specifically the for(;;); and defining serTX outside of main) and it worked perfectly. The controller is probably rebooted and hence the same code keeps repeating itself.
Thanks so much for the help! :)
Can you confirm that the 8051 really is sending the data only once? One way to check would be to use a scope to see what is happening on the UART's TX pin.
What software are you using on the PC? I'd suggest using simple communications software like HyperTerminal or PuTTY. If they are showing the string being sent to the PC multiple times, then chances are the fault is in the software running on the 8051.
EDIT: To be honest, this sounds like the kind of debugging that engineers have to face on a regular basis, and so it's a good opportunity for you to practise good old-fashioned methodical problem-solving.
If I may be very blunt, I suggest you do the following:
Debug. Try things out, but don't guess. Experiment. Make small changes in your code and see what happens. Try everything you can think of. Search the web for more information.
If that doesn't produce a solution, then return here, and provide us with all the information we need. That includes relevant pieces of the code, full details of the hardware you're using, and information about what you tried in step 1.
EDIT: I don't have the rep to edit the question, so here's the code posted by the OP in the comment to her question:
#include<reg51.h>
void SerTx(unsigned char);
void main(void)
{
TMOD = 0x20; TH1 = 0xFD; SCON = 0x50; TR1 = 1;
SerTx('O'); SerTx('N'); SerTx('L'); SerTx('Y');
void SerTx(unsigned char x)
{ SBUF = x; while(TI==0); TI = 0; }
}
As Neil and Brooksmoses mention in their answers, in an embedded system, the main function is never allowed to terminate. So you either need to put your code in an infinite loop (which may be what is inadvertently happening), or add an infinite loop at the end, so the program effectively halts.
Also, the function SerTx should be defined outside main. This may be syntatically correct, but it keeps things simple not declaring functions within other functions.
So try this (I've also added some comments in an attempt to make the code easier to understand):
#include<reg51.h>
void SerTx(unsigned char);
void main(void)
{
/* Initialise (need to add more explanation as to what
each line means, perhaps by replacing these "magic
numbers" with some #defines) */
TMOD = 0x20;
TH1 = 0xFD;
SCON = 0x50;
TR1 = 1;
/* Transmit data */
SerTx('O'); SerTx('N'); SerTx('L'); SerTx('Y');
/* Stay here forever */
for(;;) {}
}
void SerTx(unsigned char x)
{
/* Transmit byte */
SBUF = x;
/* Wait for byte to be transmitted */
while(TI==0) {}
/* Clear transmit interrupt flag */
TI = 0;
}
The code you posted has no loop in main(), so you need to determine what your compiler's C runtime does when main() returns after sending 'Y'. Given your problem, I imagine the compiler generates some code to do some cleanup then restart the micro (maybe a hardware reset, maybe just be restarting the C runtime). It looks like your program works exactly as you've written it, but you've ignored what happens before and after main() is called.
If you want your string sent once and only once, ever, then you need something like while(1) {} added after the last character is sent. But, then your program is doing nothing -- it will just execute an empty loop forever. A reset (such as power cycling) is needed to start again, and send the string.
Note that if your micro has a watchdog timer, it might intervene and force an unexpected reset. If this happens, your string will be sent once for each watchdog reset (which could be something like once each second, with the rate depending on your hardware).
Also, having serTx() defined nested inside main() is probably not what you want.
It's hard to say what the problem is without seeing any of the 8051 code. For example, a logic error on that side could lead to the data being sent multiple times, or the 8051 software might be waiting for an ACK which is never received, etc.
Normally on an 8051 code has to explicitly send each character, but I assume this is taken care of for you by the C run-time.
Use of the RTS/CTS (Request To Send/Clear To Send) is for flow control (i.e. to prevent buffer overruns - the buffers are usually pretty small on these microcontrollers) and not to stop transmission altogether.
Echoing Neil's answer (in a reply, since I don't yet have the rep to comment): In a typical microcontroller situation without an OS, it's not immediately clear what the exit() function that gets implicitly called at the end of main() should do -- or, more accurately, it can't do the usual "end the program and return to the OS", because there's no OS to return to.
Moreover, in a real application, you almost never want the program to just stop, unless you turn off the system. So one thing that the exit() implementation should definitely not do is take up a lot of code space.
In some systems I've worked on, exit() is not actually implemented at all -- if you're not going to use it, don't even waste a byte on it! The result is that when the execution path gets to the end of main(), the chip just wanders off into a lala land of executing whatever happens to be in the next bit of memory, and typically quickly ends up either stuck in a loop or faulting with an illegal opcode. And the usual result of a fault with an illegal opcode is ... rebooting the chip.
That seems like a plausable theory for what's happening here.

Resources