|
|
View previous topic :: View next topic |
Author |
Message |
krogers
Joined: 10 Apr 2009 Posts: 4
|
PIC24f: Only getting first 5 bytes read from RS232 |
Posted: Thu Apr 23, 2009 11:09 am |
|
|
I'm not sure what's going on, but when sending data to the PIC over RS232 I'm only getting the first 5 bytes that I send.
The PIC is a PIC24FJ128GA006 Dev kit, compiled with PCD 4.091.
Here's the code that's got RS232 in it:
Code: |
#include <24fj128ga006.h>
#include <stdlib.h>
#build (stack=256)
#fuses NOPROTECT,NOWDT //Use internal oscillator /*pic24 fuses*/
#use delay(clock=8000000, internal)
#use rs232(baud=9600,parity=N,bits=8, UART1, ERRORS,stream=payload)
#use rs232(baud=9600,parity=N,bits=8, UART2,stream=sensor)
#int_rda
void serial_isr() {
getInput();
processInput();
if (output) // if output needed
{
fprintf(payload, "%s\r\n", msg);
output = FALSE; // reset output flag
}
}
/*******************************************************************************
* UART2 ISR
* Function called when data is available in UART2 buffer
******************************************************************************/
#int_rda2
void serial_isr2()
{
sensor_rx = TRUE;
fprintf(payload, "data found on UART2\r\n");
getSensorInput();
}
void main(void) {
//uint32_t batChkDelay = 0; // for extending time between checks
//uint32_t batChkMult = 0; //For extending time between checks
// Initialize PIC configuration (set clock and pins)
Init();
set_timer1(0);
//setup_counters(RTCC_INTERNAL, RTCC_DIV_256);
enable_interrupts(int_rda);
enable_interrupts(int_rda2);
enable_interrupts(int_rtc);
enable_interrupts(INTR_GLOBAL);
//sleep();
while(TRUE);//{sleep();}
}
/*******************************************************************************
* Function to get input from sensor over RS232.
******************************************************************************/
void getSensorInput(void)
{
char buffer[512] = {0};
uint16_t i = 0;
long timeout;
while(i < 512)
{
while(FALSE == kbhit(sensor) && (++timeout < 5000))
{
delay_us(100);
}
if(kbhit(sensor))
{
buffer[i] = fgetc(sensor);
//if(buffer[i] == 0x04)
// break;
i++;
timeout = 0;
}
else
{
fprintf(payload, "Timeout of rs232 read\r\n");
fprintf(payload, "buffer contains %s\r\n", buffer);
fprintf(payload, "got %d bytes from UART2\r\n", i);
return;
}
}
}
void Init(void) {
// Set Oscillator
osccon=0x70; //0111000 changing the setting of bits 6-4 sets internal oscillator to 8MHz
delay_ms(500); // give it a chance to settle before garbling output
output_high(PIN_G2);
output_high(PIN_G3);
//#endif
//setup_uart(1, payload, UART_WAKEUP_ON_RDA); // sets the RDA/rs232 interrupt to wakeup from sleep mode
sprintf(msg, "\r\nCompiled on %s at %s", __DATE__, __TIME__);
PutLine(msg);
//disable_interrupts(INT_RTCC);
}
|
right now when I test it by sending it data over the second UART it receives only the first 5 bytes of data, and then on subsequent data transfers it repeats the last byte received 5 times.
I'm sending it data with `echo "ABCDEFG" > /dev/ttyS0`
This is the result:
Compiled on 23-Apr-09 at 12:09:20
data found on UART2
Timeout of rs232 read
buffer contains ABCDE
got 5 bytes from UART2
data found on UART2
Timeout of rs232 read
buffer contains EEEEE
got 5 bytes from UART2
data found on UART2
Timeout of rs232 read
buffer contains EEEEE
got 5 bytes from UART2
I can also send it data with a python script and get the same results. |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Thu Apr 23, 2009 12:27 pm |
|
|
Simply, the lengthy debug output from the interrupt procedure is causing an receiver FIFO overflow. Such operations must be avoided in an interrupt, unless you have a buffered RS232 output.
The problem isn't actually related to PIC24. |
|
|
krogers
Joined: 10 Apr 2009 Posts: 4
|
|
Posted: Thu Apr 23, 2009 1:18 pm |
|
|
I removed all the printfs from the interrupt code, have the while(TRUE) loop in main printing the contents of the buffer I'm copying into every so often, and now it's getting the first 6 bytes and repeating that 6th byte on every getc after it. So as the buffer fills it starts as:
ABCDEF
ABCDEFFFFFFF
ABCDEFFFFFFFFFFFFF
...
What I really don't understand is why it gets stuck on that last byte, it never seems to clear it from where it's reading. For what it's worth, if I send less than 5 bytes it works consistently the way I'd expect. |
|
|
Ttelmah Guest
|
|
Posted: Thu Apr 23, 2009 3:01 pm |
|
|
Look at how the serial is handled in EX_SISR.
This is the approach you need to use. As a general rule, always get out of interrupts as soon as possible.
Best Wishes |
|
|
asmallri
Joined: 12 Aug 2004 Posts: 1635 Location: Perth, Australia
|
|
Posted: Thu Apr 23, 2009 7:44 pm |
|
|
Looks like your delay function call in the ISR is the culprit. In general, if you need to delay more than a few us total in an ISR then you are not using ISRs correctly. _________________ Regards, Andrew
http://www.brushelectronics.com/software
Home of Ethernet, SD card and Encrypted Serial Bootloaders for PICs!! |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Fri Apr 24, 2009 1:08 am |
|
|
Quote: | In general, if you need to delay more than a few us total in an ISR then you are not using ISRs correctly. | Right!
And it's also not the intended normal operation of an ISR to stay in a loop waiting for the next characters. I'm not sure, what's causing exactly the UART to freeze. Most likely it's an overrun. It's not cleared in your code, cause ERRORS isn't specified for this UART.
Anyway, you should change your design towards regular interrupt processing. That means, receive the characters to a buffer in the ISR, possibly set some flags to signal events, receiption of trigger characters and so on. And process the received data respectively react on the flags in the main loop, issue debug messages without haste. |
|
|
Guest
|
|
Posted: Fri Apr 24, 2009 8:26 am |
|
|
Thanks for the help, I've made some more changes so that I'm in and out of the ISR as quick as I can, and letting the main loop handle the reading from the UART. But now I only get the first two bytes from the RS232. Also I enabled the errors, but I can't find any documentation that explains what rs232_errors means.
Code: |
#int_rda2
void serial_isr2()
{
sensor_rx = TRUE;
return;
}
void main(void) {
// Initialize PIC configuration (set clock and pins)
Init();
set_timer1(0);
enable_interrupts(int_rda);
enable_interrupts(int_rda2);
enable_interrupts(int_rtc);
enable_interrupts(INTR_GLOBAL);
while(TRUE)
{
if(sensor_rx)
{
getSensorInput();
if(rs232_errors)
{
fprintf(payload, "rs232_errors = 0x%x\r\n", rs232_errors);
rs232_errors = 0;
}
}
}
}
void getSensorInput(void)
{
while(sb_index < 511)
{
if(kbhit(sensor))
{
sensor_buffer[sb_index] = fgetc(sensor);
//if(buffer[sb_index] == 0x04)
// break;
sb_index++;
}
else
{
break;
}
}
sensor_rx = FALSE;
fprintf(payload, "sensor buffer: %s\r\n", sensor_buffer);
return;
}
|
Compiled on 24-Apr-09 at 10:05:28
sensor buffer: A
rs232_errors = 0x11
sensor buffer: AB
rs232_errors = 0x13
sensor buffer: ABA
rs232_errors = 0x11
sensor buffer: ABAB
rs232_errors = 0x13
sensor buffer: ABABA
rs232_errors = 0x11
sensor buffer: ABABAB
rs232_errors = 0x13 |
|
|
Ttelmah Guest
|
|
Posted: Fri Apr 24, 2009 8:44 am |
|
|
Your 'new' ISR, is not any better.
With this, you might as well not use the ISR at all.
As I said before, look at EX_SISR.
The interrupt code should do the _single job_, associated with the simple fact that _one_ character _is_ ready in the hardware. Nothing more, and _nothing less_. You new code does _less_...
ERRORS, is documented in the manual, in the sense of telling you that this will cause the compiler to add code to clear hardware errors. Then look further down the #use RS232 entry for the definitions of the RS232_ERRORS variable. It is though the automatic operation of clearing the hardware errors, that is important in terms of not causing a lockup.
Best Wishes |
|
|
asmallri
Joined: 12 Aug 2004 Posts: 1635 Location: Perth, Australia
|
|
Posted: Fri Apr 24, 2009 8:51 am |
|
|
This is an example of what a receive interrupt handler should look like:
Code: | #int_RDA
void serial_isr()
{
RxBaseC[RxHeadC++]=getc();
if (RxHeadC >= RxCQsize)
RxHeadC = 0;
} |
This assumes you used the ERRORS option in the #use RS232 directive
Here is an equivalent function for a compiler (C18) that does not have automatic handling of errors
Code: | #pragma interruptlow COMM1_isr
void COMM1_isr(void)
///////////////////////////////////////////////////////////////////////////
// Interrupt Handler for COM1 UART receive interrupt
///////////////////////////////////////////////////////////////////////////
{
// test for overrun error
if (RCSTAbits.OERR)
{
RCSTAbits.CREN=0; // clear continous receive bit
RCSTAbits.CREN=1; // set continous receive bit
}
RxBaseC[RxHeadC++]=RCREG;
if (RxHeadC >= RxCQsize)
RxHeadC = 0;
} |
_________________ Regards, Andrew
http://www.brushelectronics.com/software
Home of Ethernet, SD card and Encrypted Serial Bootloaders for PICs!! |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|