Serial communication problems between two Picaxe 20X2s

NXTreme

Senior Member
It's been a while since I last was on the forums, but I'm back again with another question/problem. I've been working on a multiple temperature sensor display project, using two Picaxe 20X2 chips, six DS18B20 temperature sensors and a SparkFun 16x2 SerLCD all wired together as show below (minus all the extra little bits and pieces used to get it working). The Picaxe connected to the SerLCD is what I call the "master" and the one with the six sensors attached is the "slave". Where I'm having problems is with the communications between master and slave. When first powered up, the sensor values will update just fine but after 3-5 minutes something locks up and the sensor values don't update.

After a bit of research, my problem seems to stem from inaccurate serial speeds that are caused by using 'serout' and 'serin' (http://www.picaxeforum.co.uk/showthread.php?20342-Solving-Serin-amp-Serout-Problems-with-20M2-and-20X2). I found that the suggested "good" speeds to use do extend the time before the the program locks up. 9600_8 only updates ~3 times before locking up, as will 2400_8 and 4800_8 whereas anything at __00_16 will usually update ~15 times before locking up.

I know that the circuitry works correctly as it used to work correctly. However, the slave Picaxe became physically damaged and, when replaced with a new one, my problems began. Part of the problem might be that the previous slave chip was firmware version C.0 while the new one is C.2. The master chip has C.1. I'm wondering what I can do to get this working properly. Would issuing the correct 'calibfreq' command work to get the chips synced and communicating properly? And if it would, can anyone suggest a good method of finding the right values? I don't currently have access to an oscilloscope or many tools, aside from my computer and a simple multimeter. I'm traveling right now and don't have access to all the stuff I normally do.

A quick fix would be to use 'hserout' and 'hserin' but unfortunately, after it worked at first I soldered the circuits up and glued them into two project enclosures. And when I say glued, I really mean it. It is impossible to remove the boards to work on now. This is meant to work in somewhat extreme environments (-20 to 40 degrees Celsius, lots of dust and vibrations) otherwise I wouldn't have fixed everything together so tightly.

I would greatly appreciate any help or insight anyone has.

Master program:
Code:
	#no_table
	
	symbol SerCom=B.1 'the bi-directional pin used to communicate with the slave
	symbol SerLCD=A.0 'the pin which the SparkFun SerLCD module is connected to
	
	symbol Temp0=b5 'the six temperature sensor values
	symbol Temp1=b6
	symbol Temp2=b7
	symbol Temp3=b8
	symbol Temp4=b9	
	symbol Temp5=b10
	
	symbol Counter=w8 'timer/counter for refreshing the sensor values
	
	low SerCom 'initializes slave connection
	high SerLCD 'initializes LCD connection
	pause 1000 'wait for SparkFun Splash screen to dissapear
	
inits:	pause 15
	serout SerLCD,T9600_8,(254,1) 'clear screen	
	pause 15
	serout SerLCD,T9600_8,(254,128) 'set pointer to line one, space one
	pause 15
	serout SerLCD,T9600_8,("Initializing se-nsors...")
	
	serout SerCom,N4800_8,(%01010101,"D") 'asks slave for sensor values
	serin [8000,errr],SerCom,N4800_8,("D"),Temp5,Temp4,Temp3,Temp2,Temp1,Temp0 'receives sensor values
	
	
	if Temp0>128 then 'no need for negative temperatures, so just let them equal zero if they are negative
	let Temp0=0
	endif
	
	if Temp1>128 then
	let Temp1=0
	endif
	
	if Temp2>128 then
	let Temp2=0
	endif
	
	if Temp3>128 then
	let Temp3=0
	endif
	
	if Temp4>128 then
	let Temp4=0
	endif
	
	if Temp5>128 then
	let Temp5=0
	endif
		
	pause 15
	serout SerLCD,T9600_8,(254,1) 'clear screen	
	pause 15
	serout SerLCD,T9600_8,(254,128) 'set pointer to line one, space one
	pause 15
	serout SerLCD,T9600_8,("1=",#Temp0," 2=",#Temp1," 3=",#Temp2) 'displays the sensor values received
	pause 15
	serout SerLCD,T9600_8,(254,192) 'set pointer to line two, space one
	pause 15
	serout SerLCD,T9600_8,("4=",#Temp3," 5=",#Temp4," 6=",#Temp5)

	goto tpdsy
	
	
updte:	pause 15
	serout SerLCD,T9600_8,(254,143)
	pause 15
	serout SerLCD,T9600_8,("*")
	
	serout SerCom,N4800_8,(%01010101,"D")
	serin [8000,errr],SerCom,N4800_8,("D"),Temp5,Temp4,Temp3,Temp2,Temp1,Temp0
	
	if Temp0>128 then
	let Temp0=0
	
	elseif Temp1>128 then
	let Temp1=0
	
	elseif Temp2>128 then
	let Temp2=0
		
	elseif Temp3>128 then
	let Temp3=0
		
	elseif Temp4>128 then
	let Temp4=0
		
	elseif Temp5>128 then
	let Temp5=0
	endif
	
	pause 15
	serout SerLCD,T9600_8,(254,1)	
	pause 15
	serout SerLCD,T9600_8,(254,128)
	pause 15
	serout SerLCD,T9600_8,("1=",#Temp0," 2=",#Temp1," 3=",#Temp2)
	pause 15
	serout SerLCD,T9600_8,(254,192)
	pause 15
	serout SerLCD,T9600_8,("4=",#Temp3," 5=",#Temp4," 6=",#Temp5)
	
tpdsy:	if Counter=1500 then
	let Counter=0
	goto updte
	endif
	
	pause 5
	inc Counter
	
	goto tpdsy
	
errr:	pause 15
	serout SerLCD,T9600_8,(254,128)
	pause 15
	serout SerLCD,T9600_8,("Error! Check        connection! ")
	let Counter=1400
Slave code:
Code:
; *******************************
;    Date: Feb. 15th 2011
;    Written by: NXTreme
;    Function: End goal to send 6 temp values to master when needed
;    Last Revision: V0.1
;    Target PICAXE: 20x2
; *******************************

	#no_table

	symbol SerCom=C.7
	
	symbol Temp5=b5
	symbol Temp4=b4	
	symbol Temp3=b3
	symbol Temp2=b2
	symbol Temp1=b1
	symbol Temp0=b0
	
	low SerCom

main:	serin SerCom,N4800_8,("D")
	
	readtemp C.5,Temp5
	readtemp C.4,Temp4
	readtemp C.3,Temp3
	readtemp C.2,Temp2
	readtemp C.1,Temp1
	readtemp C.0,Temp0
	
	serout SerCom,N4800_8,(%01010101,"D",b5,b4,b3,b2,b1,b0)
	goto main
Picaxe Temperature Project.png
 

Grogster

Senior Member
What is the purpose of the %01010101 in your serout commands?
Is this supposed to be a sync byte - capital U - to sync the connection?

If that is the case, I would most likely remove it.
PICAXE is a smart device, and GENERALLY does not need sync bytes.
RF modules etc do, as they have nothing, and you do need to sync the data-slicer in these things(depending on device), but I have never bothered with PICAXE, and it always just works.

Taking your slave code, the first byte it receives is going to be a "U" not a "D"
The second byte sent by the master is the "D" and that is what the slave is listening for, but if it were me, I would just change the line(in the master code):

serout SerCom,N4800_8,(%01010101,"D")

to

serout SerCom,N4800_8,("D")

And see if it works.

Likewise, I would also change:

serout SerCom,N4800_8,(%01010101,"D",b5,b4,b3,b2,b1,b0)

to:

serout SerCom,N4800_8,("D",b5,b4,b3,b2,b1,b0)

in the slave code.
 

NXTreme

Senior Member
What is the purpose of the %01010101 in your serout commands?
Is this supposed to be a sync byte - capital U - to sync the connection?
Yes, that is what it is supposed to be. I was previously having problems with it not connecting or missing the initial byte or two, which is why I added it. However, I certainly will try and see if it helps at all. Thanks!
 

Grogster

Senior Member
Another thing to try would be sending D three or four times, so that if the slave does not catch the first one, it should catch the 2nd or 3rd one.

serout SerCom,N4800_8,("DDDD")

and

serout SerCom,N4800_8,("DDDD",b5,b4,b3,b2,b1,b0)

Might not help, but could be worth a try.
 

hippy

Ex-Staff (retired)
After a bit of research, my problem seems to stem from inaccurate serial speeds that are caused by using 'serout' and 'serin' (http://www.picaxeforum.co.uk/showthread.php?20342-Solving-Serin-amp-Serout-Problems-with-20M2-and-20X2). I found that the suggested "good" speeds to use do extend the time before the the program locks up.
I'm not convinced it is a SERIN / SEROUT baud rate issue of itself but a scope could be the only way to definitively assess that. At what temperature are you you seeing the lock-up happen ?

IMO it wasn't a good choice to go for a single bi-directional serial line between the two as that adds unknowns into the equation. What is the full circuit diagram for the link ? What happens if both get control of the bus or when neither has control of the bus ?

Is there at least a pull-down on the signal line ? If not then after sending the "D" from master to slave, both have the bus as input so it effectively becomes floating and prone to electrical interference which could be messing things up. That could certainly explain the missing or corrupt data you have been seeing.

Even if it is not a serial command baud rate issue as such, there may be issues which arise at extremes of temperature and a comms method tolerant to any system frequency variation would be better.

That's still possible to implement but there's a moral here about prematurely boxing things up in impenetrable casing before you have everything tested and proven to work.
 

NXTreme

Senior Member
Yes, that is what it is supposed to be. I was previously having problems with it not connecting or missing the initial byte or two, which is why I added it. However, I certainly will try and see if it helps at all. Thanks!
Well, I tried removing the %01010101 but to no avail. It was worth a try anyways!

At what temperature are you you seeing the lock-up happen ?
Well, lately testing has been at a steady 18 degrees Celsius. I haven't been testing it in those somewhat 'extreme' environments yet.

IMO it wasn't a good choice to go for a single bi-directional serial line between the two as that adds unknowns into the equation. What is the full circuit diagram for the link ? What happens if both get control of the bus or when neither has control of the bus ?

Is there at least a pull-down on the signal line ? If not then after sending the "D" from master to slave, both have the bus as input so it effectively becomes floating and prone to electrical interference which could be messing things up. That could certainly explain the missing or corrupt data you have been seeing.

Even if it is not a serial command baud rate issue as such, there may be issues which arise at extremes of temperature and a comms method tolerant to any system frequency variation would be better.
In retrospect, yes, I should have gone with two uni-directional lines. All I have is a resistor between the two Picaxe chips, the value of which is between one and two kilo ohms. If you think a pull-down resistor would improve the chances of it working, I could probably still fit it in there without to many problems. The resistor already in place might cause problems though, what do you recommend about it?

That's still possible to implement but there's a moral here about prematurely boxing things up in impenetrable casing before you have everything tested and proven to work.
I completely agree. And that's what is bugging me about this project. It was working, I tested it thoroughly beforehand, but then when I swapped out the slave Picaxe, this bug was introduced.


Another thing to try would be sending D three or four times, so that if the slave does not catch the first one, it should catch the 2nd or 3rd one.
I think what would happen would be that if the slave missed one or two of the first Ds it would only catch two or three and get stuck waiting for more. However, I did try sending 'serout SerCom,N__00__,("D",b5,b4,b3,b2,b1,b0)' twice in a row, in case it was missed the first time. It didn't seem to make much of a visible difference though. Until I have a way of scoping things out, I won't know for sure :).
 

AllyCat

Senior Member
Hi,

I'm not an expert on PICaxe serial comms and I don't know what you're able to change with your setup (e.g. the software at both ends?) but it definitely seems a good idea to add a pull-down resistor as hippy suggests. Quite a high value (e.g. 100k) should "tame" the float, but the series resistor would have negligible effect. Alternatively, could you invert the comms (both ends) and use the internal weak pull-ups?

Would issuing the correct 'calibfreq' command work to get the chips synced and communicating properly? And if it would, can anyone suggest a good method of finding the right values?
Certainly I would try using calibfreq, perhaps + and - 2% to see if the comms get better or worse. A semi-scientific test could be to transmit say $7F or $80 (a single transition near the end of the byte), if it's received as $3F ($C0) or $FF ($00) then you know there's a timing error and can work out the direction. Also, I believe that the raw PIC hardware tests for a valid stop bit, so you might be able to peeksfr the error flag.

Cheers, Alan.
 

NXTreme

Senior Member
I'm not an expert on PICaxe serial comms and I don't know what you're able to change with your setup (e.g. the software at both ends?) but it definitely seems a good idea to add a pull-down resistor as hippy suggests. Quite a high value (e.g. 100k) should "tame" the float, but the series resistor would have negligible effect. Alternatively, could you invert the comms (both ends) and use the internal weak pull-ups?
I can easily upload new programs to both master and slave and the hardware on the master is mostly accessible. Would a 100k pull-down on the master side of the in-line resistor work fine? If I remember correctly, the internal pull-ups are 47k, right? That would work fine I think. If I did enable the pull-up resistors, would it be better to enable them on both ends, or rather one?

Certainly I would try using calibfreq, perhaps + and - 2% to see if the comms get better or worse. A semi-scientific test could be to transmit say $7F or $80 (a single transition near the end of the byte), if it's received as $3F ($C0) or $FF ($00) then you know there's a timing error and can work out the direction. Also, I believe that the raw PIC hardware tests for a valid stop bit, so you might be able to peeksfr the error flag.
I'll just play around with the values and see then. Just out of curiosity, do you (or anyone else for that fact) know how the 'calibfreq' values compare to percentages or KHz? Thanks for the other tips, I'll try them out if all else fails.

One other idea I had was to just reset both Picaxe chips, the master right before updating sensor values and the slave right after. The startup time should be less than 50-100 ms or so, which would be fine. I'll try all these ideas out, given enough time and that none of the others work. Thanks all!
 

AllyCat

Senior Member
Hi,

The pull-down/up only needs to be "large" compared with the 1-2k series resistor and could be at either end (or both). Almost any (high) value should be better than the "infinity" of two inputs linked together. Similarly, enabling a pull-up at one end should be sufficient provided that it only has "output hi/lo" and "input with pullup" states and doesn't go to "floating input" (which would occur after a reset).

I think I read that the calibfreq steps are +/- 1%, maybe in the original PIC data sheet. A simple test might be possible, send a single "simple" character (e.g. $80) from one end and measure the length of the pulse with a pulsin on the receive pin at the other end.

Cheers, Alan.
 
Top