|
|
View previous topic :: View next topic |
Author |
Message |
mvanvliet
Joined: 02 Jun 2009 Posts: 123 Location: The Netherlands
|
RS232 data corrupt |
Posted: Fri Nov 29, 2013 6:46 am |
|
|
CCS version: 5.013
After updating from version 4 to version 5 I have some problems with RS232. The data is corrupt:
<ID00><L1><PA><FA><MA~<WC><FA><CJ> 6P39<E>
<ID00><L1><PA><FA><MA~<WC><FA><CJ> 6P39<E>
<ID00><L1><PA><FA><MA|<WC><FA><CJ> 6P39<E>
<ID00><L1><PA><FA><MA><WC><FA><CJ> 6P39<E>
<ID00><L1><PA><FA><MA><WC><FA><CJ> 6P39<E>
<ID00><L1><PA><FA><MA~<WC><FA><CJ> 6P39<E>
<ID00><L1><PA><FA><MA~<WC><FA><CJ> 6P39<E>
<ID00><L1><PA><FA><MA~<WC><FA><CJ> 6P39<E>
As you can see after <MA there must be an >, in my case it are 3 different characters. I do use an interrupt routine in my software, is there something changed in version 5 which can cause this problem? And are there things I can try to solve this problem? |
|
|
oxo
Joined: 13 Nov 2012 Posts: 219 Location: France
|
|
Posted: Fri Nov 29, 2013 7:13 am |
|
|
post the code, and how big is your serial buffer? |
|
|
mvanvliet
Joined: 02 Jun 2009 Posts: 123 Location: The Netherlands
|
|
Posted: Fri Nov 29, 2013 7:21 am |
|
|
The problem is with sending RS232 from my microcontroller to a ledbar, but for testing I use my pc at this moment. The ledbar uses an XOR checksum at the end of the string, with this corrupt data the led bar doesn't show the text.
I use the FTDI RS232 to USB convertor for testing with my pc.
Code: | #include <16F1825.H>
#case
#fuses INTRC_IO,NOWDT
#fuses PUT,NOMCLR,PROTECT,CPD //CODEPROTECT EN DATAPROTECT AANGEZET
#fuses BROWNOUT,NOCLKOUT,NOIESO
#fuses NOFCMEN,NOWRT,PLL_SW
#fuses NOSTVREN,NODEBUG,NOLVP
#device ADC=8
#use delay(clock=4MHz) //Fuses and delay are set, so int osc is set at 4Mhz.
#use rs232(baud=9600, uart1, ERRORS, stream=COM_A)
#use rs232(baud=9600, xmit=PIN_C5, ERRORS, stream=COM_B) //Normal RS232
#define ACP_DATA PIN_A0 //AN0 ICP_data / TX
#define ICP_CLOCK PIN_A1 //AN1 ICP_clk / RX
//#define MODE PIN_A2 //AN2 5V spanning ADC
#define MCLR PIN_A3 // MCLR actief
//#define PULS_IN PIN_A4 //AN3 Charger on
//#define PULS_OUT PIN_A5 // Debug
#define SCK PIN_C0 //AN4 Uitgang voor uitlezen uitgangsspanning en uitgangsstroom
#define SDI PIN_C1 //AN5 Battery voltage ADC
#define SDO PIN_C2 //AN6 Battery on
#define CONTROL PIN_C3 //AN7 Battery current 2,5V +/- current
//#define PIN_C4 // Control Pin
//#define TX PIN_C5 // PWM OUTPUT
#bit TXCKSEL = getenv("BIT:TXCKSEL") // TX poortje
#bit T1GSEL = getenv("BIT:T1GSEL") //
#byte IOCAP = getenv("SFR:IOCAP")
#byte IOCAN = getenv("SFR:IOCAN")
#byte IOCAF = getenv("SFR:IOCAF")
#byte INLVLA = getenv("SFR:INLVLA")
// Oud, werkt niet in V5 compiler
//#bit ResetRequest = getenv("BIT:IOCAF3") //Flag of interrupt on pin change RA3
//#bit KoekInDetected = getenv("BIT:IOCAF4") //Flag of interrupt on pin change RA4
//#bit PakUitDetected = getenv("BIT:IOCAF5") //Flag of interrupt on pin change RA5
// Nieuw
#bit ResetRequest = IOCAF.3 //Flag of interrupt on pin change RA3
#bit KoekInDetected = IOCAF.4 //Flag of interrupt on pin change RA4
#bit PakUitDetected = IOCAF.5 //Flag of interrupt on pin change RA5
#include <string.h>
#define STATS_UPDATE_RATE 1 // Statistics update rate [minutes]
#define SECONDS_UPDATE_RATE 2 // Secounds counter update rate [seconds]
#define USB_UPDATE_RATE 60 // USB data update rate [minutes]
int8 mode = 0;
int8 ticks = 0;
int8 pak_koeken = 0;
int8 minuteCounterStatsUpdate = STATS_UPDATE_RATE;
int8 secondsCounterDisplay = SECONDS_UPDATE_RATE;
int8 minuteCounterUsb = USB_UPDATE_RATE;
int8 Minuut_teller_array = 0;
//signed int16 Verlies_array[60];
int16 Verlies_array[60];
int8 pakkoeken_array[60];
int8 urenteller = 0;
int8 aantalKoekInPak = 0;
//signed int32 KoekIn_minuut = 0;
//signed int32 KoekUit_minuut = 0;
//signed int16 VerliesPromille_minuut = 0; // Use promille instead of procent for an extra digit after the dot precision
int32 KoekIn_minuut = 0;
int32 KoekUit_minuut = 0;
int16 VerliesPromille_minuut = 0;
float pakkengemiddeld = 0;
float Verlies_uur = 0;
char type[40];
// Timer2 interrupt. Triggers every 40ms
// Handles all software based timers.
// Timers are decremented every second or every minute and stop counting when they reach 0.
// In the main() routine the timer having reached 0 will be detected and action is taken.
// It is the responsibility of the main() function to load a new timer value again after the action is finished.
#INT_TIMER2
void timer2_isr()
{
static int8 seconds = 0;
ticks++;
// When 1 second passed
if (ticks >= 25) // 25 * 40ms == 1sec.
{
ticks = 0;
seconds++;
// Update all software based seconds timers
if (secondsCounterDisplay) secondsCounterDisplay--;
}
// When 1 minute passed
if (seconds >= 60)
{
seconds = 0;
// Update all software based minute timers
if (minuteCounterStatsUpdate) minuteCounterStatsUpdate--;
if (minuteCounterUsb) minuteCounterUsb--;
}
}
void init()
{
setup_oscillator(OSC_4MHZ | OSC_PLL_OFF);
setup_dac(DAC_OFF);
setup_vref(VREF_OFF);
setup_adc_ports(sAN2 | VSS_VDD);
setup_adc(ADC_CLOCK_DIV_16); // Built-in A/D setup function TAD is 2µSec
//setup_timer_0(T0_DISABLED); // Timer0 can't be disabled on a PIC16
setup_timer_1(T1_INTERNAL | T1_DIV_BY_8); //
setup_timer_2(T2_DIV_BY_16, 250, 10); // Setup for 25Hz (4MHz / 4 Fosc / 16 Prescaler / 250 load value / 10 postscaler = 25Hz)
setup_ccp1(CCP_OFF); // Configure CCP1
setup_ccp2(CCP_OFF);
//set_tris_c(0x1A);
T1GSEL = 0; // T1_GATE_A4 instructie doet het niet vandaar handmatig.
IOCAP = 0b00110000; // RA4 en RA5 positieve flank
IOCAN = 0b00001000; // RA3 negatieve flank
IOCAF = 0;
INLVLA = 0b00111000; // RA3, A4 and A5 as Schmitt-Trigger
set_adc_channel(2); //Check modeswitch
memset(Verlies_array, sizeof(Verlies_array), 0);
memset(pakkoeken_array, sizeof(Verlies_array), 0);
// Start up delay. Allow RS232 capacitors to charge, etc.
delay_ms(2000);
enable_interrupts(INT_TIMER2);
enable_interrupts(GLOBAL);
}
void read_mode_switch()
{
int8 mode = 0;
/////////Selectie////////
set_adc_channel(2); //Check modeswitch
delay_us(20);
mode = read_adc();
if (mode < 32) //Zou ideaal 0 zijn
{
type = "<CJ> 8P";
aantalKoekInPak = 8;
}
else if (mode < 96) //Zou ideaal 64 zijn
{
type = "<CJ> 6P";
aantalKoekInPak = 6;
}
else if (mode < 143) //Zou ideaal 128 zijn
{
type = "<CJ> 4P";
aantalKoekInPak = 4;
}
else if (mode < 175) //Zou ideaal 159 zijn
{
type = "<CJ> 3P";
aantalKoekInPak = 3;
}
else if (mode < 224) //Zou ideaal 191 zijn
{
type = "<CJ> 2P";
aantalKoekInPak = 2;
}
else //Zou ideaal 255 zijn
{
type = "<CJ> 1P";
aantalKoekInPak = 1;
}
}
void calculate()
{
//Koeken in gedetecteerd
if (KoekInDetected)
{
delay_ms(10);
KoekIn_minuut += 12;
KoekInDetected = 0;
}
//Pak uit gedetecteerd
if (PakUitDetected)
{
delay_ms(10);
KoekUit_minuut += aantalKoekInPak;
pak_koeken++;
PakUitDetected = 0;
}
//Reset
if (ResetRequest)
{
delay_ms(10);
KoekIn_minuut = 0;
KoekUit_minuut = 0;
VerliesPromille_minuut = 0;
pak_koeken = 0;
ResetRequest = 0;
}
if(KoekIn_minuut >= KoekUit_minuut)
{
VerliesPromille_minuut = ((KoekIn_minuut - KoekUit_minuut) * 1000) / KoekIn_minuut;
}
else
{
VerliesPromille_minuut = ((KoekIn_minuut - KoekUit_minuut) * 1000) / KoekUit_minuut;
}
}
void update_long_term_statistics()
{
int8 i;
float pakkenTotaal = 0;
//int16 uurTotaal = 0; // maximum 60 minutes * 1000 promille loss = 60.000, does fit into an int16
float uurTotaal = 0; //delen door int16 maakt geen getal achter de komma,
//compiler deelt waarschijnlijk eerst, rond dan af en zet dan pas in float "Verlies_uur".
Verlies_array[Minuut_teller_array] = VerliesPromille_minuut;
for (i = 0; i <= Minuut_teller_array; i++)
{
uurTotaal += Verlies_array[i]; //calculate the total of the numbers in the array
}
Verlies_uur = ((uurTotaal/10)/(Minuut_teller_array + 1));
pakkoeken_array[Minuut_teller_array] = pak_koeken;
for (i = 0; i <= Minuut_teller_array; i++)
{
pakkenTotaal += pakkoeken_array[i]; //calculate the total of the numbers in the array
}
pakkengemiddeld = (pakkenTotaal/(Minuut_teller_array + 1));
if (Minuut_teller_array < 59)
{
Minuut_teller_array++;
}
else
{
Minuut_teller_array = 0;
}
ResetRequest = 1; //reset counters after 1 minute
}
void memory_stick()
{
char sUur[30];
char sData[20];
char sVerlies_uur[10];
int8 size;
TXCKSEL = 1;
sprintf(sUur,"%u,", urenteller);
sprintf(sData,"%u,", aantalKoekInPak);
//sprintf(sKoekin, "%g,", KoekIn_minuut);
//strcat(sData, sKoekin);
//sprintf(sKoekuit, "%g,", KoekUit_minuut);
//strcat(sData, sKoekuit);
sprintf(sVerlies_uur, "%3.1g%%\r\n", Verlies_uur);
strcat(sUur, sData);
strcat(sUur, sVerlies_uur);
size = strlen(sUur);
// create file and open it
fprintf(COM_A, "OPW Data.txt\r");
// write to file
fprintf(COM_A, "WRF ");
fputc(0x00, COM_A); // number of bytes of data
fputc(0x00, COM_A);
fputc(0x00, COM_A);
fputc(size, COM_A);
fputc('\r', COM_A);
fprintf(COM_A, "%s", sUur);
// close the file
fprintf(COM_A, "CLF Data.txt\r");
delay_ms(10); // Allow data in the UART Tx buffer to flush (2 bytes at 9600 baud ~= 2ms)
TXCKSEL = 0;
}
void update_lichtkrant()
{
int8 checksum;
char sVerlies_kort[10];
char sVerlies_uur[10];
char pretype[28] = "<L1><PA><FA><MA><WC><FA>";
char color[5];
char color2[5];
char totaltype[51];
//sprintf(sVerlies_kort, "%2.1g", pakkengemiddeld);
//Verlies_lang
//sprintf(sVerlies_uur, "%5.1g%%", Verlies_uur);
//if (VerliesPromille_minuut <= 30)
//{
// strcopy(color,"<CE>");
//}
//else
//{
// strcopy(color,"<CC>");
//}
// if (Verlies_uur <= 3)
// {
// strcopy(color2,"<CE>");
// }
// else
// {
// strcopy(color2,"<CC>");
// }
/////////RS232 String////////////////////
checksum = 0;
//fprintf(COM_B, "%3.0g ", KoekIn_minuut);
//fprintf(COM_B, "%3.0g\r\n", KoekUit_minuut);
strcpy(totaltype, pretype); //totaltype now contains a copy of pretype
//strcat(totaltype, color2); //add color to string
//strcat(totaltype, sVerlies_uur); //add sVerlies_half_uur to string
strcat(totaltype, type);
//strcat(totaltype, color); //it is now the two strings one after the other
//strcat(totaltype, sVerlies_kort); //add sVerlies_kort to string
for(int i = 0; i < strlen(totaltype); i++)
{
checksum ^= totaltype[i];
}
fprintf(COM_B, "<ID00>");
fprintf(COM_B, "%s",totaltype);
fprintf(COM_B, "%02X",checksum);
fprintf(COM_B, "<E>");
}
//////////////////////////////// MAIN LOOP /////////////////////////////////////
/*
<ID00> = ID
<L1> = Line
<PA> = Page
<FE> = Scroll left
<MA> = display time
<WC> = speed
<FE> = Scroll left
*/
void main()
{
init();
while(1)
{
read_mode_switch();
calculate();
if (minuteCounterStatsUpdate == 0)
{
minuteCounterStatsUpdate = STATS_UPDATE_RATE; // every minute
update_long_term_statistics();
}
if (minuteCounterUsb == 0)
{
minuteCounterUsb = USB_UPDATE_RATE; //every hour
urenteller++;
memory_stick();
}
if (secondsCounterDisplay == 0)
{
secondsCounterDisplay = SECONDS_UPDATE_RATE; // every 2 seconds
update_lichtkrant();
}
}
} |
|
|
|
mvanvliet
Joined: 02 Jun 2009 Posts: 123 Location: The Netherlands
|
|
Posted: Fri Nov 29, 2013 8:20 am |
|
|
I did some tests with other text and it is not always the same character which is corrupt:
<ID00><L1><PA><FA>|MA><WC><FA><CJ> 6P€÷4E<E>
<ID00><L1><PA><FA><MA><WC><FA><CJ> 6P€÷4E<E>
<ID00><L1><PA><FA><MA><WC><FA><CJ> 6P€÷4E<E>
<ID00><L1><PA><FA>xMA><WC><FA><CJ> 6P€÷4E<E>
<ID00><L1><PA><FA>xMA><WC><FA><CJ> 6P€÷4E<E>
<ID00><L1><PA><FA>xMA><WC><FA><CJ> 6P€÷4E<E>
<ID00><L1><PA><FA>|MA><WC><FA><CJ> 6P€÷4E<E>
<ID00><L1><PA><FA><MA><WC><FA><CJ> 6P€÷4E<E>
<ID00><L1><PA><FA><MA><WC><FA><CJ> 6P€÷4E<E>
<ID00><L1><PA><FA>xMA><WC><FA><CJ> 6P€÷4E<E>
<ID00><L1><PA><FA>|MA><WC><FA><CJ> 6P€÷4E<E>
<ID00><L1><PA><ŽA><MA><WC><FA><CJ> 6PAKKEN73<E>
<ID00><L1><PA><ŒA><MA><WC><FA><CJ> 6PAKKEN73<E>
<ID00><L1><PA><FA><MA><WC><FA><CJ> 6PAKKEN73<E>
<ID00><L1><PA>|FA><MA><WC><FA><CJ> 6PAKKEN73<E>
<ID00><L1><PA>xFA><MA><WC><FA><CJ> 6PAKKEN73<E>
<ID00><L1><PA><ŒA><MA><WC><FA><CJ> 6PAKKEN73<E> |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9226 Location: Greensville,Ontario
|
|
Posted: Fri Nov 29, 2013 8:26 am |
|
|
maybe, just maybe....
...thinking out loud here as I don't use that chip but...
#use rs232(baud=9600, xmit=PIN_C5, ERRORS, stream=COM_B) //Normal RS232
If this is the hardware UART by NOT specifying a rcv pin, CCS generates a 'software' UART and the program doesn't use the builtin hardware UART ?
If this is true , it could account for the 'corrupt' data due to timing issues.
hth
jay |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Fri Nov 29, 2013 8:54 am |
|
|
He will get corrupted data on COM_B, every time the timer ticks, while a character is being sent. COM_A should be fine ('uart1', specifies both pins for you).
It is the COM_B data that is corrupted, so this is what is happening, but this would have happened with the old compiler as well. Not changed with V5....
Are you sure your timer was running?. There was a bug in certain V4 versions, and present in the early V5 versions, where printf/sprintf. could leave the GIE bit disabled. This would have stopped the timer from interfering with the serial, but would have left the timer not running. This was fixed at about 5.011.
Add the keyword 'DISABLE_INTS' to the COM_B rs232 declaration, which will then delay the timer interrupt to the end of the character.
Best Wishes |
|
|
mvanvliet
Joined: 02 Jun 2009 Posts: 123 Location: The Netherlands
|
|
Posted: Fri Nov 29, 2013 9:03 am |
|
|
It seems that disable_ints is solving my problem, but why I noticed it first with my update to version 5....I don't know. I'm going to try it on the lightbar in an hour. Thank you Ttelmah.
With version 4 I had 4.113 or so, so the GIE bit bug was solved, but can be inserted again in version 5... |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Fri Nov 29, 2013 9:21 am |
|
|
It is one of these 'there', 'not there', 'there again', 'not there' bugs.
It was reported at one point in V4. Fixed, for a few versions, then re-appeared. Then was fixed again, then re-appeared again. Then was fixed again, and then re-appeared slightly changed in V5.
The fact that the data was not being corrupted with V4, really does tend to imply the GIE was disabled.
When I started trying to find which versions didn't have this problem, I was surprised at how many did....
Update.
I realise this is the core of your problem.
On the older compilers, they appeared on several versions to disable interrupts during printf, which (of course), meant your timer didn't interfere with the transmission, but (unfortunately), means that your timer interrupt would have been delayed for the entire transmission, and serial interrupts and other things that needed to happen, would also get delayed, with the possibility of characters being missed...
The faulty compilers then failed to turn the interrupts back on.
Then with the fix on V5, the interrupts are not disabled at all, which then (of course - again), introduces your problem.
So anyone who is using software serial with anything that uses interrupts, now needs to use the 'DISABLE_INTS' option.
Best Wishes |
|
|
jgschmidt
Joined: 03 Dec 2008 Posts: 184 Location: Gresham, OR USA
|
|
Posted: Fri Nov 29, 2013 10:15 pm |
|
|
Jumping in with a followup question...
I see that mvanvliet is running the processor at 4mhz when he could be running at 32mhz. Would there be less chance of corruption running at higher speeds? _________________ Jürgen
www.jgscraft.com |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Sat Nov 30, 2013 12:33 am |
|
|
The corruption might not be bad enough to cause problems at higher speeds.
Basically the time taken to handle the interrupt would drop by a factor of 8, which given the 'margins' in async serial, might make it short enough to 'get away' with.
Currently the interrupt would take perhaps 100uSec, which then gives a 10% timing error. At 32MHz, the error would only be perhaps 1.5%.
Best Wishes |
|
|
|
|
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
|