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

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.

Related

C: Is there a way to lower the speed of printf-outputs

as said in the heading, is there a way to lower the speed of printf-outputs in C? Just like watching every character getting printed in particular (it does not have to be so slow, just so you understand what i mean).
The reason why i ask is:
I need to program a small microcontroller. But every 'printf' executed on it should be send back to the com1 port of the host. Everything works fine, I already buffered my printf so everything will be stored in a char-array with a finit size and this array will be sent back to com1 char by char. But because i don't know how many printfs there will be, and because of the limited memory of the μC, a size-limited array isn't the best solution. So my new attempt is to write directly to the send-register of the μC, which can only contain one char at a time until its sent. I do this via
setvbuf(stdout, LINFLEX_0.BDRL.B.DATA0, _IOFBF, 1);
where LINFLEX_0.BDRL.B.DATA0 represents the transmit-register. What I think what my problem is now: the printfs just overwrite the register to fast, so it has no time to send any char stored in it before it gets changed again. When sending char by char from the array, i wait until a data-transmission-flag is set:
//write character to transmit buffer
LINFLEX_0.BDRL.B.DATA0 = buffer[j];
// Wait for data transmission completed flag
while (1 != LINFLEX_0.UARTSR.B.DTF) {}
// Clear DTF Flag
LINFLEX_0.UARTSR.R = 0x0002;
So the idea is to slower the speed the printfs processes every character, but feel free to comment if anyone has another idea.
The problem isn't with printf as such but with the underlying UART driver. That's what you'd have to tweak. If you are using Codewarrior for MPC56 you can actually view the source code for all of it: quite horrible code. Messing with it will only go bad - and apparently it doesn't seem to work well in the first place.
Using printf in these kind of embedded applications is overall a very bad idea, since the function is unsuitable for pretty much any purpose, UART communication in particular. The presence of printf is actually an indicator that a project has gone terribly wrong, quite possibly it has been hijacked by PC programmers. That's not really a programming problem, but a manager one.
Technically, the only sane thing to do here is to toss out all the crap from your project. That means everything remotely resembling stdio.h. Instead, write your own UART driver, based on the available Freescale examples. Make it work on bytes. This also enables you to add custom features such as "echo", where the MCU has to wait for a reply from the receiver. Or you could implement it with DMA if you just want to write data to a buffer and then forget all about it.

FRDM K82f uart interrupt only fires about 8 times

I am currently having trouble getting the LPUART interrupt to work properly on the NXP FRDM K82f board with MCUXpresso IDE using MCUXpresso SDK.
The LPUART interrupt only fires 6-8 times and never again after that.
This behavior is independent from the current position in the code. I tested it by sending the first batch of data long after the program enters the infinite loop and also by sending it right at the start of the program (after lpuart interrupt initialization). Same behavior in both cases.
This is my initialization routine and the interrupt handler.
#include <stdint.h>
#include "fsl_lpuart.h"
#define OSCERCLK_SOURCE 2U
#define ESP_UART LPUART0
#define UART_IRQ LPUART0_IRQn
#define UART_RECEIVE_INTERRUPT LPUART0_IRQHandler
#define BUFFER_SIZE 2048
volatile uint8_t ringBuffer[BUFFER_SIZE] = {0x00};
volatile uint16_t rxIndex = 0;
volatile uint16_t txIndex = 0;
void init(uint32_t baudRate){
lpuart_config_t config;
CLOCK_SetLpuartClock(OSCERCLK_SOURCE);
LPUART_GetDefaultConfig(&config);
config.baudRate_Bps = baudRate;
config.enableRx = true;
config.enableTx = true;
uint32_t clockFrequency = CLOCK_GetFreq(kCLOCK_Osc0ErClk);
LPUART_Init(ESP_UART, &config, clockFrequency);
LPUART_EnableInterrupts(ESP_UART, kLPUART_RxDataRegFullInterruptEnable);
EnableIRQ(UART_IRQ);
}
void UART_RECEIVE_INTERRUPT(void){
uint8_t data;
uint32_t flags = kLPUART_RxDataRegFullFlag & LPUART_GetStatusFlags(ESP_UART);
if (flags){
data = LPUART_ReadByte(ESP_UART);
if((rxIndex + 1) % BUFFER_SIZE != txIndex){
ringBuffer[rxIndex] = data;
rxIndex++;
rxIndex %= BUFFER_SIZE;
}
}
}
Has anybody encountered a similar behavior and is able to help?
EDIT:
As #Lundin suggested I corrected the non-standard gcc syntax.
No success yet, but I was able to track what flags are set when the ISR doesn't fire anymore.
The set flags are:
kLPUART_TxDataRegEmptyFlag,
kLPUART_IdleLineFlag,
kLPUART_RxOverrunFlag,
kLPUART_RxFifoEmptyFlag
This looks ambiguous to me, because RX FIFO is empty and also RX is overrun.
One of the first things you need to figure out is if you are using the FIFO, or simply dealing with the single-character receive data register. If you are not using the FIFO, then the FIFO flag is irrelevant, and it is unsurprising that it shows empty.
As to the overrun flag, the programmer's manual is unsurprisingly explanatory:
Receiver Overrun Flag
OR is set when software fails to prevent the receive data register from overflowing with data. The OR bit is
set immediately after the stop bit has been completely received for the dataword that overflows the buffer
and all the other error flags (FE, NF, and PF) are prevented from setting. The data in the shift register is
lost, but the data already in the LPUART data registers is not affected....
This suggests the distinct possibility that at some point in the past you failed to claim data before it would have been overwritten, setting the overrun flag. But if you also had a delayed response to the original receive data interrupt, you could have read the original data without awareness of the problem. However, if you did so, and left the overrun flag on, that would be the last data you ever received.
It seems like there are at least three things you need to do:
Fully implement or fully ignore the optional FIFO mode
Check the overrun flag, clear it to see if it makes a difference, but also find a way to indicate (set a sticky volatile software flag, toggle a GPIO watched by a scope in one time trigger mode, whatever) to indicate that a problem has occurred, so that you can take steps to investigate that.
Analyze and test your program overall for design faults which might yield to failure to respond to serial data quickly enough. This could include things like toggling a GPIO in the ISR and watching that and the serial data line on a scope, putting timer checks into the code, and auditing all other ISRs and any foreground options which must disable interrupts. Also try stripping your program down until you simply have something that receives and echos characters and experiment with that, both hitting keys one at a time in a terminal program, and having a program inject strings at a rate which keeps the serial line 100% busy.
Also keep in mind that while break point debugging can be very powerful, with any program that must respond to external events, it is quite likely that operation will no longer be normal after the first time the breakpoint is hit, so to approach a problem in that way you often need to design tests which end at the point where the breakpoint is hit and you analyze only the state collected up to that point. Sometimes this means you need to an an "if" condition so that you can put a breakpoint inside of it.
The problem is most probably about Receiver Overrun flag. As it is stated in reference manual of the processor, after overrun flag has set, no more new data has come to receiver buffer/FIFO even if sufficient room exists.
Don't forget that even if you don't call the LPUART_ReadByte() function, the characters entered to your UART port has saved into UART buffer and after you call ReadByte it first reads the previous entered characters. If you overcommit to UART port and fill its buffer, it sets the Overrun flag and refuses to take more input characters from that port.
The thing you should do is, clearing the Overrun flag after it is anyhow set. It would be better if you check overrun flag and if it is set, clear it by yourself manually.
if(kLPUART_RxOverrunFlag & LPUART_GetStatusFlags(ESP_UART))
{LPUART_ClearStatusFlags(ESP_UART,kLPUART_RxOverrunFlag);}
You can check for this flag and clear it every before you want to read a data from your UART.

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.

Relaying UART1 with UART2 within an ISR() (PIC24H)

I am programming a microcontroller of the PIC24H family and using xc16 compiler.
I am relaying U1RX-data to U2TX within main(), but when I try that in an ISR it does not work.
I am sending commands to the U1RX and the ISR() is down below. At U2RX, there are databytes coming in constantly and I want to relay 500 of them with the U1TX. The results of this is that U1TX is relaying the first 4 databytes from U2RX but then re-sending the 4th byte over and over again.
When I copy the for loop below into my main() it all works properly. In the ISR(), its like that U2RX's corresponding FIFObuffer is not clearing when read so the buffer overflows and stops reading further incoming data to U2RX. I would really appreciate if someone could show me how to approach the problem here. The variables tmp and command are globally declared.
void __attribute__((__interrupt__, auto_psv, shadow)) _U1RXInterrupt(void)
{
command = U1RXREG;
if(command=='d'){
for(i=0;i<500;i++){
while(U2STAbits.URXDA==0);
tmp=U2RXREG;
while(U1STAbits.UTXBF==1); //
U1TXREG=tmp;
}
}
}
Edit: I added the first line in the ISR().
Trying to draw an answer from the various comments.
If the main() has nothing else to do, and there are no other interrupts, you might be able to "get away with" patching all 500 chars from one UART to another under interrupt, once the first interrupt has ocurred, and perhaps it would be a useful exercise to get that working.
But that's not how you should use an interrupt. If you have other tasks in main(), and equal or lower priority interrupts, the relatively huge time that this interrupt will take (500 chars at 9600 baud = half a second) will make the processor what is known as "interrupt-bound", that is, the other processes are frozen out.
As your project gains complexity, you won't want to restrict main() to this task, and there is no need to for it be involved at all, after setting up the UARTs and IRQs. After that it can calculate π ad infinitum if you want.
I am a bit perplexed as to your sequence of operations. A command 'd' is received from U1 which tells you to patch 500 chars from U2 to U1.
I suggest one way to tackle this (and there are many) seeing as you really want to use interrupts, is to wait until the command is received from U1 - in main(). You then configure, and enable, interrupts for RXD on U2.
Then the job of the ISR will be to receive data from U2 and transmit it thru U1. If both UARTS have the same clock and the same baud rate, there should not be a synchronisation problem, since a UART is typically buffered internally: once it begins to transmit, the TXD register is available to hold another character, so any stagnation in the ISR should be minimal.
I can't write the actual code for you, since it would be supposed to work, but here is some very pseudo code, and I don't have a PIC handy (or wish to research its operational details).
ISR
has been invoked because U2 has a char RXD
you *might* need to check RXD status as a required sequence to clear the interrupt
read the RXD register, which also might clear the interrupt status
if not, specifically clear the interrupt status
while (U1 TXD busy);
write char to U1
if (chars received == 500)
disable U2 RXD interrupt
return from interrupt
ISR's must be kept lean and mean and the code made hyper-efficient if there is any hope of keeping up with the buffer on a UART. Experiment with the BAUD rate just to find the point at which your code can keep up, to help discover the right heuristic and see how far away you are from achieving your goal.
Success could depend on how fast your micro controller is, as well, and how many tasks it is running. If the microcontroller has a built in UART theoretically you should be able to manage keeping the FIFO from overflowing. On the other hand, if you paired up a UART with an insufficiently-powered micro controller, you might not be able to optimize your way out of the problem.
Besides the suggestion to offload the lower-priority work to the main thread and keep the ISR fast (that someone made in the comments), you will want to carefully look at the timing of all of the lines of code and try every trick in the book to get them to run faster. One expensive instruction can ruin your whole day, so get real creative in finding ways to save time.
EDIT: Another thing to consider - look at the assembly language your C compiler creates. A good compiler should let you inline assembly language instructions to allow you to hyper-optimize for your particular case. Generally in an ISR it would just be a small number of instructions that you have to find and implement.
EDIT 2: A PIC 24 series should be fast enough if you code it right and select a fast oscillator or crystal and run the chip at a good clock rate. Also consider the divisor the UART might be using to achieve its rate vs. the PIC clock rate. It is conceivable (to me) that an even division that could be accomplished internally via shifting would be better than one where math was required.

Why do we need to delay when sending char to serial port?

Consider this code here:
// Stupid I/O delay routine necessitated by historical PC design flaws
static void
delay(void)
{
inb(0x84);
inb(0x84);
inb(0x84);
inb(0x84);
}
What is port 0x84? Why is it a design flaws? delay() is used in serial_putc() function:
static void
serial_putc(int c)
{
int i;
for (i = 0;
!(inb(COM1 + COM_LSR) & COM_LSR_TXRDY) && i < 12800;
i++)
delay();
outb(COM1 + COM_TX, c);
}
The file is from lab1 of the course Operating System Engineering from OCW.
The serial port is a piece of hardware with some semantic you have to accept. It usually has a shift register that makes the conversion from parallel to serial data. It can have a holding register for the next byte to send or even a FIFO for more than one byte. That's why you have to poll the line status register (LSR).
There are some hardware revisions out there that doesn't behave correctly. Your code looks like a workaround for a bug in old hardware. It shouldn't be necessary to read the port 0x84 here.
But the delay implementation can't be optimized out when you increase the compiler optimization level since it's accessing the I/O range. Running this code in a up-to-date hardware might be problematic if the run-time performance gives too little delay. You will have to verify that the maximum time that can be waited in the loop is sufficient to shift out one byte by the UART. Keep in mind that this is baudrate-dependend while you code example isn't.
The port 0x84 is used to access the "extra page register" (Overview). But reading this register should be a noop. Only the read operation itself is important to consume CPU cycles.

Resources