|
|
View previous topic :: View next topic |
Author |
Message |
kbrown@hysecurity.com
Joined: 07 May 2014 Posts: 9 Location: Seattle
|
Dual serial port and string capture |
Posted: Mon Nov 03, 2014 5:43 pm |
|
|
Hi All -
I've a problem that I've run into. It must be some sort of Monday thing ;)
Anyway, I have a PIC16F1526 in which I am attempting to use the dual hardware serial port functionality there of. Serial port 1 (UART1) is being used as debug. Serial port 2 is being used to talk to a peripheral. For the sake of argument, let's assume said peripheral can only ever generate 8-byte data, as seen in the code below.
If I hook up two tera-terms (on a PC via TTL converters) to the two serial ports, I can watch data single byte transfer all day long. Yawn. Now if I send the 8-byte chunk all at once, the second serial port only captures the first 2 bytes and misses the next 6. Send again, and again only the first 2 bytes are captured. If I Rinse and repeat 4 times, I can fill the buffer of the second port and get out (albeit wrong) data buffer.
I am monitoring the data in and out of the serial port with a tool called "AccessPort". I can see the data transferred via single bytes as the bytes that make it across. I can see the bytes transferred all at once only receive the first 2. I'm not detecting any RS232_ERRORS if I watch that variable
What poor sap mistake have I made?
Code: |
#include <16F1526.h>
//directives
#fuses INTRC_IO,NOWDT,NOPROTECT,NOMCLR,BROWNOUT,PUT, BORV25
#device ADC=10
#use delay(clock=16000000)
#use rs232(baud=115200, xmit=PIN_C6, rcv=PIN_C7, stream=PC, STOP=1, UART1)
#use rs232(baud=38400, xmit=PIN_G1, rcv=PIN_G2, STOP=1, bits=8, parity=n, stream=MMB, ERRORS, UART2)
#define LED_GREEN1_ON output_low(PIN_E0)
#define LED_GREEN2_ON output_low(PIN_E1)
#define LED_GREEN3_ON output_low(PIN_E2)
#define LED_GREEN4_ON output_low(PIN_E3)
#define LED_GREEN5_ON output_low(PIN_E4)
#define LED_GREEN6_ON output_low(PIN_G0)
#define LED_GREEN1_OFF output_high(PIN_E0)
#define LED_GREEN2_OFF output_high(PIN_E1)
#define LED_GREEN3_OFF output_high(PIN_E2)
#define LED_GREEN4_OFF output_high(PIN_E3)
#define LED_GREEN5_OFF output_high(PIN_E4)
#define LED_GREEN6_OFF output_high(PIN_G0)
#define LED_RED1_ON output_low(PIN_F5)
#define LED_RED2_ON output_low(PIN_F6)
#define LED_RED1_OFF output_high(PIN_F5)
#define LED_RED2_OFF output_high(PIN_F6)
#define BUFFER_SIZE 23
char buffer[BUFFER_SIZE];
int next_in = 0;
int f=0;
char mmb_buffer[BUFFER_SIZE];
int mmb_next_in = 0;
int SET_LEDS(int on, int sled) {
if (on) {
if(sled==1){ LED_GREEN1_ON; }
else if (sled==2) {LED_GREEN2_ON; }
else if (sled==3) {LED_GREEN3_ON; }
else if (sled==4) {LED_GREEN4_ON; }
else if (sled==5) {LED_GREEN5_ON; }
else if (sled==6) {LED_GREEN6_ON; }
else if (sled==7) {LED_RED1_ON; }
else if (sled==8) {LED_RED2_ON; }
}else{
if(sled==1){ LED_GREEN1_ON; }
else if (sled==2) {LED_GREEN2_OFF; }
else if (sled==3) {LED_GREEN3_OFF; }
else if (sled==4) {LED_GREEN4_OFF; }
else if (sled==5) {LED_GREEN5_OFF; }
else if (sled==6) {LED_GREEN6_OFF; }
else if (sled==7) {LED_RED1_OFF; }
else if (sled==8) {LED_RED2_OFF; }
}
}
int LEDS_OFF(){
int i =0;
for(i=0; i<8; i++){ SET_LEDS(0, i); }
}
int serial2_handler(){
//twiddle another led
output_high(PIN_G3);
int h=0;
for(h=0; h<8; h++){
fprintf(PC, "%x " mmb_buffer[h]);
}
delay_ms(2);
//twiddle another led
output_low(PIN_G3);
mmb_next_in =0;
return 0;
}
//
//
//serial interrupt
#int_rda2
void serial2_isr() {
mmb_buffer[mmb_next_in]=fgetc(MMB);
mmb_next_in++;
if(mmb_next_in>7){
serial2_handler();
}
//fputc(RS232_ERRORS, MMB);
}
void serial_handler(){
buffer[next_in]=fgetc(PC);
fputc(buffer[next_in], PC);
next_in++;
if(next_in>=BUFFER_SIZE){
//full input buffer
next_in = BUFFER_SIZE;
buffer[BUFFER_SIZE-1]=0x0D;
}
//process serial commands
if (buffer[next_in - 1] == 0x0D) {
//serial_decode();
buffer[next_in] =0;
fprintf(PC, "%s\n\r", buffer);
next_in=0;
buffer[next_in] =0;
}else if(buffer[next_in - 1] == 0x72){
fprintf(PC, "RESTTING\n\r");
reset_cpu();
}
}
//serial interrupt
#int_rda
void serial_isr() {
// int t;
serial_handler();
}
/*
*
*/
int main(int argc, char** argv) {
int a=0, b=0;
int last_restart =0;
//start up stuff
delay_ms(100);
setup_adc_ports(NO_ANALOGS);
setup_oscillator(OSC_16MHZ | OSC_INTRC);
set_tris_a(0xF7); //a = 1111 0111
set_tris_b(0xFC); //b = 1111 1100
set_tris_c(0x87); //c = 1000 0111
set_tris_d(0x00); //d = 0000 0000 all outputs
set_tris_e(0x00); //e = 0000 0000 all outputs
set_tris_f(0x9F); //f = 1001 1111
set_tris_g(0xF4); //g = 1111 0100
setup_vref(VREF_2v048 | TEMPERATURE_INDICATOR_ENABLED);
setup_adc_ports(sAN0 | sAN1 | sAN2 | sAN16 | sAN19, VSS_FVR);
setup_adc(adc_clock_div_16);
LEDS_OFF();
last_restart = RESTART_CAUSE();
fprintf(PC, "\n\rstarting 0x%X\n\r", last_restart);
//turn off led
output_high(PIN_G3);
enable_interrupts(int_rda);
enable_interrupts(int_rda2);
enable_interrupts(global);
//turn on an LED to at least see we made it this far
output_low(PIN_G3);
//do a whole lot of nothin'
while (1) {
//twidle de-dumb led
delay_ms(200);
a ^= 1 << 1;
set_leds(a, 4);
}
return (0);
}
|
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Nov 03, 2014 7:01 pm |
|
|
This should be a clue:
Quote: | >>> Warning 216 "pcm_test.c" Line 203(1,2): Interrupts disabled during call to prevent re-entrancy: (@delay_ms1)
>>> Warning 216 "pcm_test.c" Line 203(1,2): Interrupts disabled during call to prevent re-entrancy: (@PRINTF_X_115200_118_119) |
|
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9245 Location: Greensville,Ontario
|
|
Posted: Mon Nov 03, 2014 8:54 pm |
|
|
also you must add 'errors' to the use rs232(...options...) for every hardware UART you use....
Jay |
|
|
kbrown@hysecurity.com
Joined: 07 May 2014 Posts: 9 Location: Seattle
|
|
Posted: Mon Nov 03, 2014 11:07 pm |
|
|
PCM programmer wrote: | This should be a clue:
Quote: | >>> Warning 216 "pcm_test.c" Line 203(1,2): Interrupts disabled during call to prevent re-entrancy: (@delay_ms1)
>>> Warning 216 "pcm_test.c" Line 203(1,2): Interrupts disabled during call to prevent re-entrancy: (@PRINTF_X_115200_118_119) |
|
Baahaw! If I had just clicked one tab over on the build/program, I would have seen that! I told you I was having a Monday. That's also what I get for grabbing old code from another project as a base start without reviewing it ALL first. What a total bone-headed mistake.
And yes, I should include ERRORS in the #use def of the uart. Even better would be to check those errors and act upon them. But being this is all hardware bring up testing, I may cut some corners before handing off to the firmware team (oh wait, that's me this time too).
Thanks all. +5 points to PCM. |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Tue Nov 04, 2014 5:17 am |
|
|
Just some nit-picking review comments:
- You are setting the TRIS registers, but you are not specifying the CCS IO-mode. By default the compiler will then set the TRIS registers for you. Best practice is to not mix both methods; either have the compiler handle the TRIS registers for you, or you specify the TRIS in combination with the directive #USE FAST_IO.
- Code: | set_tris_a(0xF7); //a = 1111 0111 | I don't like it when the same information is presented twice, sooner or later they will mismatch and create confusion. Combine into a single statement: Code: | set_tris_a(0b11110111); |
- Code: | int main(int argc, char** argv) { |
This is an embedded program, so you'll never receive command line arguments and you'll never exit to an OS to return a value to.
- Even after 30 years the EXOR command takes me too much time to understand what this line is doing. A little bit of comment is nice to your fellow programmers. Strange is that you are toggling bit1 where the set_leds() function expects true or false, i.e. bit0.
- NEVER put a delay in interrupt routines. Now you have a 2ms delay call in serial2_handler(). This will cause overflows on the 38400 UART2 receiving.
- Add #case to your program to avoid capitalization mismatches. Now you are mixing set_leds() and SET_LEDS(). Personally I prefer only constants and macro's to be in all capitals.
- serial2_handler is returning a value. Why? It always returns 0 and the calling function isn't testing the returned value. Simplify your code by ridding the return value.
- Code: | int serial2_handler(){ | You are not returning a value, so declare the function void.
- same for SET_LEDS(). |
|
|
ezflyr
Joined: 25 Oct 2010 Posts: 1019 Location: Tewksbury, MA
|
|
Posted: Tue Nov 04, 2014 8:27 am |
|
|
Hi,
A couple of other things:
Code: |
#use rs232(baud=115200, xmit=PIN_C6, rcv=PIN_C7, stream=PC, STOP=1, UART1)
|
You should specify the pin assignments (eg. xmit=, rcv=) or the use the UART keyword(s), UART1/UART2, but not both in the #use rs232 directive.
IMO, a much more fundamental problem is that your serial interrupts are too complicated. This will ultimately cause your program to fail as you receive more data. Never put delays or print statements, etc. inside an ISR, and for that matter, never have the ISR call another subroutine. The serial ISR(s) should be simple and fast, only buffering data, and possibly setting flags (such as that a complete data 'packet' has been received). Everything else should be processed outside of the interrupt(s), such as in Main().
John |
|
|
kbrown@hysecurity.com
Joined: 07 May 2014 Posts: 9 Location: Seattle
|
|
Posted: Tue Nov 04, 2014 9:57 am |
|
|
ckielstra and ezflyr -
All good observations and points. I certainly like the 0bxxxx TRIS setting idea. I'm going to steal it. My firmware guys would hang me if I tried to release code like this after a design review. My forte is high speed analog and RF design, not programming. Sometimes the hardware can't wait for the firmware ;)
Has anyone ever collected up all the "good" tips and tricks on this forum? You guys should write a tutorial and post it here! I'm sure I'd learn something new and I'd bet others would too.
The point of this code was to test hardware, to at least get the pins to wiggle and make *something* happen. By no means would any of this ever make it out into "the real world". I got wrapped around the Monday morning axle for a dumb mistake. |
|
|
ezflyr
Joined: 25 Oct 2010 Posts: 1019 Location: Tewksbury, MA
|
|
Posted: Tue Nov 04, 2014 12:02 pm |
|
|
Hi,
The forum and the CCS supplied example programs comprise the 'tutorial' that you are looking for. Spend a little bit of time reading the forum, and studying the forum archives, and your CCS 'C' programming skills will improve immeasurably! Anything you can't answer, you can ask here, but we expect a certain 'minimum effort' (BTW, you already seem to be above that threshold!) on the users part first!
John |
|
|
|
|
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
|