PIC18F locking up if sending data to quickly - c

I'm working with a PIC18F and am trying to send data via hyperterminal. When I send data at a slow rate by pressing one key every half secondish it recieves the data and echos it correctly but when I start pressing the keys at a faster rate the MCU locks up. Not sure what causes this.
while(index<length){
while(PIR1bits.RCIF==0); // Wait till char recieved
sendData(str2,9); // confirm reception
Delay1KTCYx(5); //delay because without it, it messes up.
rxData[index]= RCREG; //char array
index++;
}
baudrate is 2400 On both PIC and hyperterminal.
This is our receive loop. sendData is just debug code that we send saying "recieved". It's how we know when it has frozen.
It does not freeze at the same amount of loops everytime, it is solely on how fast we input data.

(I did work on MCUs but haven't a deal with PICs, so i'll try to help with common problems)
You do not check any receiver error flags. Receiver may lock up in Overrun Error state and do not receive further, until you clear Overrun flag. Add check for error conditions and resolve them accordinly to PIC documentation.
Good practice is to read received byte as early, as possible when receive complete is indicated, so try to move rxData[index]= RCREG; imediately after while(PIR1bits.RCIF==0);. This lowers possibility
You didn't shown code for sendData. There may be missed checking for TX ready state and error conditions, so it may also lock up.
Unmotivated delay indicates that you're already going wrong somewhere. Try to remove it and THEN debug code.
You should test your receive and transmit separately. At first, check transmitter: try to output long line of text through UART without any receiving. (Say, write "Hello world!" program:))
Check receiver code alone: remove transmission from program, connect LED (voltmeter, oscillosocope, whatever you have) to free GPIO pin, and then make it toggle logic level on it every time it receives a byte. Is it takes only several clock ticks to do, it should not intervene receiving or lockup.

Maybe when you send 2 characters while it is busy sending the "received" one of them is discarded and you never reach your length?

On most microcontrollers, a UART receiver overrun will cause the newly-received byte to be discarded and a flag to be set, but the receiver will continue to operate normally. On the PIC, a receiver overrun will cause the UART to die until the CREN bit is cleared and re-set.

Related

On-board LED, doesn't turn on until I click reset, data receive/trasmit dosn't work correctly

I just started working with STM32F407GZ and I for the start I wanted to turn on/off LED's on-board. I am using CubeMX to generate initialization code. I can receive and transmit data but it doesn't gets correctly the data recived. Also, the leds don't turn on until I click the reset button. When I click the reset button the leds turn on but I stop receiving and transmiting data.
This is the code:
MX_GPIO_Init();
MX_DMA_Init();
MX_USART3_UART_Init();
HAL_UART_Receive_DMA(&huart3,receive,20);
while (1)
{
HAL_Delay(100);
HAL_UART_Receive_DMA(&huart3,receive,20);
HAL_UART_Transmit_DMA(&huart3,receive,20);
HAL_Delay(100);
HAL_GPIO_WritePin(GPIOF,GPIO_PIN_9,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOF,GPIO_PIN_6,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOF,GPIO_PIN_7,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOF,GPIO_PIN_8,GPIO_PIN_SET);
HAL_Delay(500);
}
HAL_UART_Receive_DMA(&huart3,receive,20);
HAL_UART_Transmit_DMA(&huart3,receive,20);
This is wrong. DMA functions are not blocking. They do not wait until the operation finishes. They return immediately. You instruct UART to receive 20 bytes and at the same moment, you want to send the data from the same buffer (and nothing has been received yet).
As 0___________ said, DMA is non blocking receive. It automatically reads data from the bus and move the data to the memory location you specified (which is receive in your case).
Here is the simple solution using blocking functions:
HAL_UART_Receive(&huart3, receive, 20, 1000);
HAL_UART_Transmit(&huart3, receive, 20, 1000);
HAL_UART_Receive() returns when either the 20 bytes of data is received or 1000 ms has been passed.
HAL_UART_Transmit() returns when either the 20 bytes of data is transmitted or 1000 ms has been passed.
These two functions make sure that the execution of receiving and transmitting follows the order of statements.
This isn't the thing that you are asking, but I think this might help you.
The part of turning on led can be reduced to one line:
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9, GPIO_PIN_SET);
You can see the definition of GPIO_PIN_6 or other pins and you will get the idea.

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.

Speed up / modify tcdrain() function

I'll skirt round the long and tedious story of how we got where we are, but the situation is this:
We are using half-duplex RS485 serial comms and (by necessity) driving the TX/RX flag "manually" via GPIO pin toggling. In order to make this work we're using tcdrain() to wait until the Tx buffer is empty before flipping back to Rx mode.
The problem is that tcdrain() seems to wait (block) for quite a while after the last character has been transmitted, which causes us a bit of a bottleneck.
I've seen suggestions that the default tcdrain() code just multiplies the baud rate by the (maximum) size of the serial buffer, sleep()s for that time period and then returns.- and I could easily believe that.
So, can anyone suggest ways to either:
Speed up tcdrain() perhaps by shortening the serial buffer
Modify tcdrain() (or related code/parameters) to actually wait for the last character to be sent by the hardware, or wait for a period more closely related to the buffer contents
I've grepped our (embedded) kernel (2.6.x) code and can't see any references other than a single header file (termios.h).
Edit to add: As per this post, if for example we could reduce the serial Tx buffer to 1 byte using an IOCTL I assume the write() call would/could block while chars were written, then return, which would allow us to avoid relying on tcdrain() and just use a very short usleep() before toggling the Tx/Rx pin. I will experiment when I get a moment, in the meantime any suggestions/examples welcome.

What does BREAK mean in real terms while using a UART?

The break and error indication glows up in real terms while communicating with RS-232. Sometimes, the CTS is also will be glowing.
Due to this, the data in prints as junk for some time; later it gets corrected after a few reset of real term.
This is a screenshot showing the error:
What does BREAK mean really? What happens when there's a break?
A break condition occurs when the transmitter is holding the data line at logical 0 for too long, i.e. longer than the time needed for transmitting a start bit and the (usually 8) data bits. Possible causes:
The transmitter can send a break deliberately, as an out-of band signal, e.g. to signal the beginning of a data packet, like in the LIN protocol.
It can occur when the transmitter is sending at a lower speed as the receiver is expecting. Perhaps its clock is not properly initialized.
Of course it can be caused by a noisy or otherwise bad connection.

Spi interrupt handler works when a printf() is used

I am trying to initiate a spi communication between an omap processor an sam4l one. I have configured spi protocol and omap is the master. Now what I see is the test data I am sending is correctly reaching on sam4l and I can see the isr is printing that data. Using more printf here and there in isr makes the operation happen and the respective operation happens, but if I remove all printfs I can't see any operation happening. What can be the cause of this anomaly? Is it a usual case of wrong frequency settings or something?
If code is needed I will post that too but its big.
Thanks
I think you are trying to print message in driver.
As printing message on console with slow down your driver, it may behave slowly and your driver work well.
Use pr_info() for debug and change setting to not come message on console by editing /proc/sys/kernel/printk to 4 4 1 7
-> It will store debug message in buffer.
-> Driver not slow down because of printing message on screen.
-> And you can see it by typing dmesg command later.
Then find orignal problem which may cause error.
If a routine works with printf "here and there" and not otherwise, almostcertainly the problem is that there are timing issues. As a trivial example, let's say you write to an SPI flash and then check its content. The flash memory write will take some times, so if you check immediately, the data would not be valid, but if you insert a printf call in between, it may have taken enough time that the read back is now valid.

Resources