Expanding outputs over multiple PICAXE chips

jsch2603

New Member
Fellow Enthusiasts,

Thank you in advance for any PICAXE programming insight and/or direction you can provide regarding my rather simple application that follows. Please excuse if this gets a bit “wordy”, but I hope that providing more info about what I am trying to do initially will be better than too little.

My basic questions can be found by jumping to the Bottom Line Questions section of this document if you wish, but for a little more in-depth please read on. Thank you.

Background:
I am relatively new to PICAXE and microcontrollers for that matter, and my basic programming knowledge has been quite limited up to this point. However, I do have many past years of electronics training and experience, so I should hopefully be able to comprehend and pick-up on your advice / instruction somewhat quickly.

Intent:
In general, I was looking for a flexible solution that would allow me to control a multi-grouped, four-color array of LED’s, when one day I happened to stumble across an application utilizing the PICAXE microcontroller. After some preliminary investigation, I was certain enough that the economical PICAXE microcontroller would in one way or another serve my application needs. Based upon my initial I/O requirements and noting some script and forum commentary that the PICAXE I/O could perhaps be expanded across to at least a second microcontroller via the serout/in commands and/or possibly the I2C bus, I proceeded to purchase (3) 40X1’s, AXE022 proto-boards and EEPROMS (not knowing if these would be needed or not as things developed). Whether these methods of I/O (primarily output) expansion would pan out was not of great importance because I felt that for what I’m trying to do that I could always configure the (3) 40X1’s to control the LED color channels individually; each board receiving their respective digital control inputs out of the projected 8-10 that will be incorporated. Somewhat undesirably, it appeared that this would also involve then having (3) separate programs, one for each 40X1 chip. I know that some of you more experienced may be shaking your heads right now - rightfully so, and that is why I think it would be best if I could consolidate the programming for all color channels into one 40X1; not only to seemingly simplify matters from the programming/downloading perspectives, but there is also the strong possibility that I may want to coordinate sequencing of the (4) multi-output LED color channels; which I would envision to be quite difficult if the control programming would be spread out over the (3) individual 40X1’s as demonstrated in the Preliminary Program Code that follows below.

Application:
My application is a relatively simple one with a couple of “catches”. As mentioned, I have a predetermined number of outputs that exceeds the capacity of a single (or two for that matter) 40X1 chip(s). Also, the color channels (Blue, Green, Amber/Red) could be controlled independently, each 40X1 tentatively assigned as shown in the following Specification and Preliminary Program Code; but with inter-color sequencing as a desired possibility, I think it best (in my naive experience to date) that the control programming be consolidated on one 40X1 chip.

General Interfacing and Control Specifications:
Fast processing speed is not overly a concern. However, in the event that the outputs of the 2nd and 3rd 40X1 chips would be controlled by either the serout/in commands or possibly the I2C bus, it would be preferred that these outputs react somewhat quickly to the input states of the 1st 40X1.

Outputs (color channels): (36) total – (11) Blue, (11) Green, (7) Amber and (7) Red.
Insignificant Note: Each output is fed to a ULN2803A which will further drive as follows: (11) groups of (7) series connected Blue LED’s (75 LED’s total), (11) groups of (7) series connected Green LED’s (73 LED’s total), (7) groups of (12) series connected Amber LED’s (74 LED’s total), and (7) groups of (12) series connected Red LED’s (73 LED’s total). Total number of LED’s = 295

Inputs: (8-10) To be opto-coupled from an existing programmable logic controller (PLC) based Modicon Compact 984A (circa 1994) 24vdc outputs and also directly from other voltage level input switches and output indicators.
Note: You may ask why I don’t just add the programming for these additional LED displays to this existing controller? The answer is that I very well could, but I’m unable to practically utilize or expand on the PLC outputs due to lack of spares available and portable enclosure limitations, not to mention parts availability and cost. Besides, I would like to learn more about the PICAXE and microcontrollers in general. I think it’s a neat little solution for this application if it can be configured to work as envisioned.

Due to length of this message I have removed my preliminary code from this location. However, I have presented it (abridged) in two subsequent posts.

Bottom Line Questions:
I don’t expect anyone to fully comprehend what I’m attempting to do here, nor is there the need for one to do so. What I’m hoping to learn as a result of this inquiry are some basic answers to the following questions, concerning possible effective use of the serout/in commands and the I2C bus for the purpose of possibly expanding the I/O to the two other 40X1 chips and having the primary program consolidated and downloaded to only one 40X1 chip; This before I would commit to fabricating any I/O interface board(s) for the microcontroller (AXE022 board) and a custom LED display board:

1. Would use of the Serin/Serout commands work for this application? And if so…
a. On the 1st 40X1 chip: Am I limited to using the 0-7 output pins (portb) or could I use the portc pins as an alternative? When bread boarding, I’ve tried to assign portc as in the last two examples of the above Test Program Code and the syntax was accepted; but when downloaded, only the corresponding portb output 7 of the 1st 40X1 flashes a test LED (serial communication?), even though I’ve essentially told it to use output 15 (portc output 7) in this case.
b. Also, when trying to send a test copy of the outpin values (e.g. %11111111) of the 1st 40X1 chip via these serial commands to the 0 input of the second 40X1 chip, only the two MSB LED’s on portb of the 2nd 40X1 chip illuminate when activating the appropriate input(s) on the 1st 40X1 chip. Upon releasing the input pushbutton(s) the remaining portb outputs of the 2nd 40X1 light only momentarily but I am not clear as to why this is based upon my test programming code. I understand that timeouts and transmission-received acknowledgments can be issues as I’ve read in the forums, but I am really not up-to-speed with much of this yet.

2. I’m just now starting to look into possible use of the I2C bus for this purpose, but in reading some posts, I am not clear if this will work simplistically and effectively between what I’m led to believe are multiple, (3) in my case, bus master? devices (40X1’s).
a. It appears that the I2C portc pins 18 and 23 (SCL/SDA) of the 40X1 need to be reserved and configured for special use with the ic2slave command, then pulled-high using a 4k7 resistor in each line. It would seem then that these pins can no longer be assigned as digital inputs or outputs; is this assessment correct? If so…
b. Would it be correct then to configure portc as follows: let dirsc = %11100111 where the “00” bits are assigned to the I2C pins (assuming one would like to configure the remaining portc pins as outputs)?

In Conclusion:
Available information concerning the use of either of these two methods appears quite sketchy and limited from what I have seen so far. If something similar to what I’m trying to accomplish in addressing multiple outputs across several PICAXE chips has been effectively done by anyone utilizing either of these methods, I would greatly appreciate any insight.

In retrospect, perhaps there‘s a more suitable approach / product to handle this, but I plan to persevere with the PICAXE nonetheless. Thanks again so much for your help.
 
Last edited:

jsch2603

New Member
Expanding outputs over multiple PICAXE chips (2)

Here is some abridged Preliminary Program Code (referred to in the main message) presently written for (3) separate 40X1 chips that I would like to consolidate into one chip if control of the outputs of the 2nd and 3rd chip can be done via the 1st 40X1 chip. (no serout / serin commands):

Code:
;BOARD #1 (40X1-1) - BLUE LED CONTROL

symbol LEDBLU_G00 = 0 		; rename output0 ‘LEDBLU_G00’
symbol LEDBLU_G01 = 1 		; rename output1 ‘LEDBLU_G01’
symbol LEDBLU_G02 = 2 		; rename output2 ‘LEDBLU_G02’
symbol LEDBLU_G03 = 3 		; rename output3 ‘LEDBLU_G03’
symbol LEDBLU_G04 = 4 		; rename output4 ‘LEDBLU_G04’
symbol LEDBLU_G05 = 5 		; rename output5 ‘LEDBLU_G05’
symbol LEDBLU_G06 = 6 		; rename output6 ‘LEDBLU_G06’
symbol LEDBLU_G07 = 7 		; rename output7 ‘LEDBLU_G07’

let dirsc = %11100111	; direct the (3) portc LSBs and MSBs as outputs’

symbol LEDBLU_G08 = 8	 	; rename output8 ‘LEDBLU_G08’
symbol LEDBLU_G09 = 9		; rename output9 ‘LEDBLU_G09’
symbol LEDBLU_G10 = 10 		; rename output10 ‘LEDBLU_G10’
symbol I2C_SCL_1 = 11 		; rename output11 ‘I2C_SCL_1’
symbol I2C_SDA_1 = 12 		; rename output12 ‘I2C_SDA_1’
symbol SPARE1_3 = 13 		; rename output13 ‘SPARE1_3’
symbol SPARE1_4 = 14 		; rename output14 ‘SPARE1_4’
symbol SPARE1_5 = 15 		; rename output15 ‘SPARE1_5’

symbol SYS_RESET = pin2		; rename input pin2 ‘SYS_RESET’
symbol MAT_OffD = pin3		; rename input pin3 ‘MAT_OffD’

main:				; make a label called ‘main’

	do	; start a do loop to flash Blue LED's for the condition...
	if SYS_RESET = 0 and MAT_OffD = 1 then; if SYS_RESET input is low and MAT_OffD input is high
		let pins = %11111111		; switch all the outputs on portb high
		let portc = %00000111		; switch (3) LSB outputs on portc high
		pause 500 			; wait for 1.0 second
		let pins = %00000000		; switch all the outputs on portb low
		let pinsc = %00000000		; switch all the outputs on portc low
		pause 500 			; wait for 1.0 secon
	             loop until SYS_RESET = 0 and MAT_OffD = 0	; loop until SYS_RESET and MAT_OffD are low
	endif

	if SYS_RESET = 1 and MAT_OffD = 1 then	; and condition for SYS_RESET and MAT_OffD inputs high
		let outpins = %11111111		; switch all the outputs on portb high
		let portc = %00000111		; switch (3) LSB outputs on portc high
	else
		let outpins = %00000000		; switch all the outputs on portb low
		let portc = %00000000		; switch all the outputs on portc low
	endif
	goto main				; loop back to start
END OF 1st 40X1 PROGRAM-------------------------------------------------

Code:
;BOARD #2 (40X1-2) - GREEN LED CONTROL

symbol LEDGRN_G00 = 0 		; rename output0 ‘LEDGRN_G00’
symbol LEDGRN_G01 = 1 		; rename output1 ‘LEDGRN_G01’
symbol LEDGRN_G02 = 2 		; rename output2 ‘LEDGRN_G02’
symbol LEDGRN_G03 = 3 		; rename output3 ‘LEDGRN_G03’
symbol LEDGRN_G04 = 4 		; rename output4 ‘LEDGRN_G04’
symbol LEDGRN_G05 = 5 		; rename output5 ‘LEDGRN_G05’ System Reset ind.
symbol LEDGRN_G06 = 6 		; rename output6 ‘LEDGRN_G06’
symbol LEDGRN_G07 = 7 		; rename output7 ‘LEDGRN_G07’

let dirsc = %11100111	; direct the (3) portc LSBs and MSBs as outputs’

symbol LEDGRN_G08 = 8		; rename output8 ‘LEDGRN_G08’
symbol LEDGRN_G09 = 9		; rename output9 ‘LEDGRN_G09’
symbol LEDGRN_G10 = 10 		; rename output10 ‘LEDGRN_G10’
symbol I2C_SCL_2 = 11 		; rename output11 ‘I2C_SCL_2’
symbol I2C_SDA_2 = 12 		; rename output12 ‘I2C_SDA_2’
symbol SPARE2_3 = 13 		; rename output13 ‘SPARE2_3’
symbol SPARE2_4 = 14 		; rename output14 ‘SPARE2_4’
symbol SPARE2_5 = 15		; rename output15 ‘SPARE2_5’

symbol SYS_RESET = pin2		; rename input pin2 ‘SYS_RESET’
symbol HIT = pin6			; rename input pin6 ‘HIT’

symbol hit_counter = b0 		; define a counter using variable b0

main:				; make a label called ‘main’
	if SYS_RESET = 1 then	; jump if SYS_RESET input is high
		high LEDGRN_G05 	; switch output LEDGRN_G05 high
	endif
	
	if HIT = 1 then 		; if HIT input is high then...
		gosub hitseq	; sub to hitseq
	endif
	goto main
	
hitseq:				; make a label called ‘hitseq’
	if hit_counter = 3 then return; prevent re-triggering of ‘hitseq’ sub
	endif
	let pins = %00000000	; switch LEDGRN output group 00 thru 07 low
	let pinsc = %00000000	; switch LEDGRN output group 08 thru 10 low
	let pins = %00000001	; set LEDGRN output group 00 high
	pause 100		; wait for 0.1 second
	let pins = %00000010	; set LEDGRN output group 01 high
	pause 100		; wait for 0.1 second
	let pins = %00000100	; set LEDGRN output group 02 high
	pause 100		; wait for 0.1 second
	let pins = %00001000	; set LEDGRN output group 03 high
	pause 100		; wait for 0.1 second
	let pins = %00010000	; set LEDGRN output group 04 high
	pause 100		; wait for 0.1 second
	let pins = %00100000	; set LEDGRN output group 05 high
	pause 100		; wait for 0.1 second
	let pins = %01000000	; set LEDGRN output group 06 high
	pause 100		; wait for 0.1 second
	let pins = %10000000	; set LEDGRN output group 07 high
	pause 100		; wait for 0.1 second
	let pins = %00000000	; set LEDGRN output group 07 low
	let pinsc = %00000001	; set LEDGRN output group 08 high
	pause 100		; wait for 0.1 second
	let pinsc = %00000010	; set LEDGRN output group 09 high
	pause 100		; wait for 0.1 second
	let pinsc = %00000100	; set LEDGRN output group 10 high
	pause 100		; wait for 0.1 second
	let pinsc = %00000000	; set LEDGRN output group 10 low
	for hit_counter = 1 to 2 	; start a for...next loop
		let pins = %11111111	; switch LEDGRN output group 00 thru 07 high
		let pinsc = %00000111	; switch LEDGRN output group 08 thru 10 high
		pause 500 		; wait for 0.5 second
		let pins = %00000000	; switch LEDGRN output group 00 thru 07 low
		let pinsc = %00000000	; switch LEDGRN output group 08 thru 10 low
		pause 500 		; wait for 0.5 second
	next hit_counter 			; end of for...next loop
		let pins = %11111111	; switch LEDGRN output group 00 thru 07 high
		let pinsc = %00000111	; switch LEDGRN output group 08 thru 10 high
	goto main
END OF 2ND 40X1 PROGRAM------------------------------------------------

Code:
;BOARD #3 (40X1-3) - AMBER AND RED LED CONTROL

symbol LEDAMB_G00 = 0 		; rename output0 ‘LEDAMB_G00’
symbol LEDAMB_G01 = 1 		; rename output1 ‘LEDAMB_G01’
symbol LEDAMB_G02 = 2 		; rename output2 ‘LEDAMB_G02’ Air Pressure Low ind.
symbol LEDAMB_G03 = 3 		; rename output3 ‘LEDAMB_G03’
symbol LEDAMB_G04 = 4 		; rename output4 ‘LEDAMB_G04’
symbol LEDAMB_G05 = 5 		; rename output5 ‘LEDAMB_G05’
symbol LEDAMB_G06 = 6 		; rename output6 ‘LEDBLU_G06’
symbol SPARE3_1 = 7 		; rename output7 ‘SPARE3_1’

let dirsc = %11100111	; direct the (3) portc LSBs and MSBs as outputs’

symbol LEDRED_G00 = 8	 	; rename output8 ‘LEDRED_G00’
symbol LEDRED_G01 = 9		; rename output9 ‘LEDRED_G01’
symbol LEDRED_G02 = 10 		; rename output10 ‘LEDRED_G02’ Power ON ind.
symbol I2C_SCL_3 = 11 		; rename output11 ‘I2C_SCL_3’
symbol I2C_SDA_3 = 12 		; rename output12 ‘I2C_SDA_3’
symbol LEDRED_G05 = 13 	             ; rename output13 ‘LEDRED_G05’
symbol LEDRED_G06 = 14 		; rename output14 ‘LEDRED_G06’
symbol SPARE3_2 = 15		; rename output15 ‘SPARE3_2’

symbol POWER_ON = pin0		; rename input pin0 ‘POWER_ON’
symbol AIR_PRS_LOW = pin1		; rename input pin1 ‘AIR_PRS_LOW’
symbol COWARD_CPUBATT = pin4	; rename input pin4 ‘COWARD_CPUBATT’
symbol FIRE = pin7			; rename input pin7 ‘FIRE’

symbol fire_counter = b0 		; define a counter using variable b0
symbol sr_counter = b1	 	; define a counter using variable b1

; symbol SESS_END = porta pin0	; rename porta input pin0 ‘SESS_END’
; symbol SESS_RESET = porta pin1	; rename porta input pin1 ‘SESS_RESET’

main:				; make a label called ‘main’
	if POWER_ON = 1 and FIRE = 0 then	; if the POWER_ON input is high and FIRE is low then...
		let pinsc = %00000100	; set LEDRED output group 02 (power ON ind.) high
	endif

	if FIRE = 1 then gosub fireseq	; sub to fireseq if FIRE input is high
	
	if FIRE = 0 then			; if FIRE input is low then...
		let fire_counter = %00000000	; reset fire_counter
	endif

	if AIR_PRS_LOW = 1 and COWARD_CPUBATT = 0 then
		gosub airflsh		; sub to airflsh if AIR_PRS_LOW input is high
	endif
	
	if COWARD_CPUBATT = 1 then gosub coward 	; sub to coward
	if COWARD_CPUBATT = 0 then
	let pins = %00000000
	endif
	
	if porta pin0 = 1 then gosub sessend	; sub to sessend if SESS_END input is high
	
	if porta pin1 = 1 then gosub sessrst	; sub to sessend if SESS_RESET input is high
	
	if porta pin1 = 0 then		; if SESS_RESET input is low then...
		let sr_counter = %00000000	; reset sr_counter
	endif
goto main				; else loop back around

airflsh:
	high LEDAMB_G02			; set LEDAMB output group 02 high
	pause 1000			; wait for 1.0 second
	low LEDAMB_G02			; set LEDAMB output group 02 high
	return				; return from sub

coward:
	if porta pin0 = 0 then		; using a separate if statement for porta pin condition
		let pins = %01111111	; set LEDAMB output groups 00 thru 06 high
	else	let pins = %00000000
	endif
	return

fireseq:					; make a label called ‘fireseq’
	if fire_counter = 4 then return	; prevent re-triggering of ‘fireseq’ sub
	else
	for fire_counter = 1 to 3 		; start a for...next loop
		let pinsc = %01111111	; set LEDRED output groups 00 thru 06 high (less 02, power ON ind.)
		pause 500 		; wait for 0.5 second
		let pinsc = %00000000	; switch LEDRED output group 00 thru 07 low
		pause 500 		; wait for 0.5 second
	next fire_counter
	let pinsc = %01111111		; set LEDRED output groups 00 thru 06 high
	endif
	return

sessend:  ABRIDGED

sessrst:  ABRIDGED...
END OF 3rd 40X1 PROGRAM-------------------------------------------------
 

jsch2603

New Member
Expanding outputs over multiple PICAXE chips (3)

Following is some of my Test Program Code excerpts in (2) separate 40X1 chips (with serout / serin commands). Note: I’m sure there are errors in this code; it’s just a 1st attempt at using the serout and serin commands and is supplied for reference only:

Code:
;BOARD #1 (40X1-1) - BLUE LED CONTROL

symbol LEDBLU_G00 = 0 	; rename output0 ‘LEDBLU_G00’
symbol LEDBLU_G01 = 1 	; rename output1 ‘LEDBLU_G01’
symbol LEDBLU_G02 = 2 	; rename output2 ‘LEDBLU_G02’
symbol LEDBLU_G03 = 3 	; rename output3 ‘LEDBLU_G03’
symbol SER_GRN_G00_07 = 4 	; rename output4 ‘SER_GRN_G00_07’ Serial out to 40X1-2 portb ?
symbol SER_GRN_G08_10 = 5 	; rename output5 ‘SER_GRN_G08_10’ Serial out to 40X1-2 portc ?
symbol SER_AMB_G00_07 = 6 	; rename output6 ‘SER_AMB_G00_07’ Serial out to 40X1-3 portb ?
symbol SER_RED_G00_07 = 7 	; rename output7 ‘SER_RED_G00_07’ Serial out to 40X1-3 portc ?

let dirsc = %11100111	; direct the (3) portc LSBs and MSBs as outputs’

symbol LEDBLU_G04 = 8	 ; rename output8 ‘LEDBLU_G04’
symbol LEDBLU_G05 = 9	; rename output9 ‘LEDBLU_G05’
symbol LEDBLU_G06 = 10 	; rename output10 ‘LEDBLU_G06’
symbol I2C_SCL = 11 	; rename output11 ‘I2C_SCL’
symbol I2C_SDA = 12 	; rename output12 ‘I2C_SDA’
symbol LEDBLU_G07 = 13 	; rename output13 ‘LEDBLU_G07’
symbol LEDBLU_G08 = 14 	; rename output14 ‘LEDBLU_G08’
symbol LEDBLU_G09 = 15 	; rename output15 ‘LEDBLU_G09’
; symbol LEDBLU_G10 =	; note: extra output needed here

symbol SYS_RESET = pin2    ; rename input pin2 ‘SYS_RESET’
symbol MAT_OffD = pin3	; rename input pin3 ‘MAT_OffD’

symbol counter = b1 	; define a counter using variable b1

setint %00001100,%00001100	; activate interrupt when pin2 and pin3 go high

main:			; make a label called ‘main’

	let b2 = outpins 	; set b2 to pins (portb) value for testing serout
;	let b3 = pinsc 	; set b3 to pinsc (portc) value for testing serout

	serout SER_GRN_G00_07,N2400_4,(b2)
	
;	serout SER_GRN_G08_10,N2400,(b3)	
;	serout SER_AMB_G00_07,N2400,(b4)	
;	serout SER_RED_G00_07,N2400,(b5)
Remaining programming…

END OF 1st 40X1 PROGRAM (with sample serout code)-----------------------------------------------------

Code:
;BOARD #2 (40X1-2) - GREEN LED CONTROL

symbol LEDGRN_G00 = 0 		; rename output0 ‘LEDGRN_G00’
symbol LEDGRN_G01 = 1 		; rename output1 ‘LEDGRN_G01’
symbol LEDGRN_G02 = 2 		; rename output2 ‘LEDGRN_G02’
symbol LEDGRN_G03 = 3 		; rename output3 ‘LEDGRN_G03’
symbol LEDGRN_G04 = 4 		; rename output4 ‘LEDGRN_G04’
symbol LEDGRN_G05 = 5 		; rename output5 ‘LEDGRN_G05’
symbol LEDGRN_G06 = 6 		; rename output6 ‘LEDGRN_G06’
symbol LEDGRN_G07 = 7 		; rename output7 ‘LEDGRN_G07’

let dirsc = %11100111	; direct the (3) portc LSBs and MSBs as outputs’

symbol LEDGRN_G08 = 8	 	; rename output8 ‘LEDGRN_G08’
symbol LEDGRN_G09 = 9		; rename output9 ‘LEDGRN_G09’
symbol LEDGRN_G10 = 10 		; rename output10 ‘LEDGRN_G10’
symbol I2C_SCL = 11 		; rename output11 ‘I2C_SCL’
symbol I2C_SDA = 12 		; rename output12 ‘I2C_SDA’
symbol SPARE2_3 = 13 		; rename output13 ‘SPARE2_3’
symbol SPARE2_4 = 14 		; rename output14 ‘SPARE2_4’
symbol SPARE2_5 = 15		; rename output15 ‘SPARE2_5’

main:				; make a label called ‘main’
	
	serin 0,N2400_4,b1		
	let pins = b1			

;	serin 3,N2400_4,b2		
;	let pinsc = b2			

	goto main
END OF 2nd 40X1 PROGRAM (with sample serout code)-----------------------
 

westaust55

Moderator
Firstly while I have done some work with the PICAXE using i2c comms, this has been using IO expanders and i2c slave devices but not PICAXE to PICAXE comms as a master slave configuration but from what I have read this is certianly possible.

Secondly I have not looked at you program in terms of either its size or structure.

If your entire program requirements can fit into a single 40X1 then you can consider the use of i2c based IO expander chips.
there are simpler devices such as the PCF8574 with have 8 IO per chip,
there are MCP23008 devices which are a little more complex again with 8 IO per chip and
there are MCP23016 devices which have 16 IO that can be used as 2 x 8-bit ports or 1 x 16-bit port.


The PCF8574 is available in two variants the 8574 and the 8574A. The only difference is the Slave address. Each allows up to 8 chips to be uses so with just the 8574 you can have 8 x 8 = 64 IO and if you can locate the 8574A devices as well, this quantity will double to 128 IO.
Likewise you can have up to 8 of the MCP23016 chips connected to a single 40X1 which will give 8 x 16 = 128 IO.
 
Last edited:

jsch2603

New Member
Ahhh... I2C devices as I/O expanders - I was not aware of such. Did I mention that I was green at this ;o) In hindsight, perhaps I should have consulted the forum before purchase. I will look more into the I2C capabilities and devices as you mention. It would seem to be a very practical approach to the matter.

I was hoping there might be a relatively easy way to effectively address the outputs amongst the (3) 40X1 chips, since I've already aquired these and the AXE022 proto boards to go with. I notice you mention that from what you've read that configuring PICAXE to PICAXE comms as a master slave(s) is quite possible. If the method to do such is known by anyone and if it is a practical alternative, please advise.

Note: It doesn't appear as though my entire program will exceed 1/4 the capacity of a single 40X1 (purchased mainly for its increased I/O capabilities); so yes, everything should fit easily on a single 40X1.

Thank you for your time and post!
 

hippy

Technical Support
Staff member
I'm a great fan of using what you have to hand so I'd have probably used 40X1's to do as you have. So okay you did buy them for this task but I wouldn't worry too much. If you do change to I2C expanders you'll still have those 40X1's for some other project.

One tip ...

serin 0,N2400_4,b1
let pins = b1

You can improve that with ...

serin 0,N2400_4,pins

This will write directly to the output pins with no intermediate staging and is a bit quicker.
 

BCJKiwi

Senior Member
If you decide to run with I/O expanders would suggest the MCP23017 rather than the MCP23016, faster, simpler board layout and a few other enhancements.
Working examples of code in the misc projects section.
 

Technical

Technical Support
Staff member
i2c is also quite easy for expanding...

Master
Code:
hi2csetup i2cmaster, %10100000, i2cslow, i2cbyte
main:
hi2cout [%10100000],0,(newvalue1)  'write value to slave 1
hi2cout [%10110000],0,(newvalue2)  'write value to slave 2
hi2cout [%11000000],0,(newvalue3)  'write value to slave 3
etc....
goto main
Slave1
Code:
hi2csetup i2cslave, %10100000
main:
get 0,(b1)
let outpins = b1
goto main
Slave2
Code:
hi2csetup i2cslave, %10110000
main:
get 0,(b1)
let outpins = b1
goto main
Slave3
Code:
hi2csetup i2cslave, %11000000
main:
get 0,(b1)
let outpins = b1
goto main
etc....
 
Last edited:

jsch2603

New Member
Great advice all around - Thank you!
Note: By the time I finished typing this, I had noticed other posts came in as well, so my following message may be a little outdated. Nonetheless, thank you all for the additional input (Including "Technical" - I2C coding, which I will look into as well... At a glance, can the 40X1's work as the slave devices also?).

I will tinker a bit more with the serial commands and if need be perhaps go to the expanders and save the remaining 40X1's for possible future apps. as noted. Thank you all again for your advice and suggestions.

Optional Follow-up Questions:
1. In the simplified code example that follows, I show outputs 4 thru 7 assigned for serout purposes. Does anyone know if it is possible / practical to do this; in other words, to have more than one output pin assigned for serout purposes?

Note: My initial plan was to configure serial related I/O as follows for the (3) 40X1's: (Note: The following code is unverified)

40X1-1:
Ports b and c for BLU channel LEDs (less portb outputs 4 thru 7 which would be assigned as follows): Again, I don't know if this is possible
outpin4 GRN channel serout to 40X1-2 portb (via i.e. b2)
outpin5 GRN channel serout to 40X1-2 portc (via i.e. b3)
outpin6 AMB channel serout to 40X1-3 portb (via i.e. b4)
outpin7 RED channel serout to 40X1-3 portc (via i.e. b5)

40X1-2:
pin0 (input) GRN channel serin to 40X1-2 portb outputs related code:
serin 0,N2400_4,pins
pin1 (input) GRN channel serin to 40X1-2 portc outputs related code:
serin 1,N2400_4,pinsc

40X1-3:
pin0 (input) AMB channel serin to 40X1-3 portb outputs related code:
serin 0,N2400_4,pins
pin1 (input) RED channel serin to 40X1-3 portc outputs related code:
serin 1,N2400_4,pinsc

2. Must serout be used only with portb fixed ouputs - 0 thru 7, or could portc output pins be used for this purpose as well?
I didn't have much luck trying to configure / utilize portc for this purpose per my initial post. It's not a real concern however, just curious to know.

Code:
;BOARD #1 (40X1-1) - LOCAL BLUE LED CONTROL (Abridged) AND SEROUTs FOR GRN, AMBER AND RED LED CONTROL

symbol LEDBLU_G00 = 0 	             ; rename output0 ‘LEDBLU_G00’
symbol LEDBLU_G01 = 1 	             ; rename output1 ‘LEDBLU_G01’
symbol LEDBLU_G02 = 2 	             ; rename output2 ‘LEDBLU_G02’
symbol LEDBLU_G03 = 3 	             ; rename output3 ‘LEDBLU_G03’
symbol SER_GRN_G00_07 = 4 	; rename output4 ‘SER_GRN_G00_07’ Serial out to 40X1-2 portb
symbol SER_GRN_G08_10 = 5 	; rename output5 ‘SER_GRN_G08_10’ Serial out to 40X1-2 portc
symbol SER_AMB_G00_07 = 6 	; rename output6 ‘SER_AMB_G00_07’ Serial out to 40X1-3 portb
symbol SER_RED_G00_07 = 7 	; rename output7 ‘SER_RED_G00_07’ Serial out to 40X1-3 portc

let dirsc = %11100111	             ; direct the (3) portc LSBs and MSBs as outputs’

symbol LEDBLU_G04 = 8	             ; rename output8 ‘LEDBLU_G04’
symbol LEDBLU_G05 = 9	             ; rename output9 ‘LEDBLU_G05’
symbol LEDBLU_G06 = 10 	             ; rename output10 ‘LEDBLU_G06’
symbol I2C_SCL = 11 	             ; rename output11 ‘I2C_SCL’ (optional)
symbol I2C_SDA = 12 	             ; rename output12 ‘I2C_SDA’ (optional)
symbol LEDBLU_G07 = 13 	             ; rename output13 ‘LEDBLU_G07’
symbol LEDBLU_G08 = 14 	             ; rename output14 ‘LEDBLU_G08’
symbol LEDBLU_G09 = 15 	             ; rename output15 ‘LEDBLU_G09’
; symbol LEDBLU_G10 =	             ; note: extra output needed here... Possibly use outpin 11 or 12 if serin/out option is used

symbol SYS_RESET = pin2                 ; rename input pin2 ‘SYS_RESET’
symbol MAT_OffD = pin3	             ; rename input pin3 ‘MAT_OffD’

main:			             ; make a label called ‘main’
	serout SER_GRN_G00_07,N2400_4,(b2)
	serout SER_GRN_G08_10,N2400_4,(b3)	
	serout SER_AMB_G00_07,N2400_4,(b4)	
	serout SER_RED_G00_07,N2400_4,(b5)
 
Last edited:

westaust55

Moderator
Great advice all around - Thank you!
:
:
At a glance, can the 40X1's work as the slave devices also?).
:
:

2. Must serout be used only with portb fixed ouputs - 0 thru 7, or could portc output pins be used for this purpose as well?
I didn't have much luck trying to configure / utilize portc for this purpose per my initial post. It's not a real concern however, just curious to know.
To answer some of your questions:
can the 40X1's work as the slave devices also?
Yes, only the X1 parts (28X1 and 40X1) can be set up as slave devices.

Must serout be used only with portb fixed ouputs - 0 thru 7?
Yes, the serout command only works with the 8 port B outputs. Port C can only be used for simpler functions such as toggling high and low. Commands such as SEROUT, PULSE, etc

Have a look at this thread: http://www.picaxeforum.co.uk/showthread.php?t=9497&highlight=PortC
 
Last edited:

inglewoodpete

Senior Member
Must serout be used only with portb fixed ouputs - 0 thru 7?
Yes, but...

hSerout/hSerin uses 2 dedicated Port C pins and offers more flexibility for handling serial. This is my preferred option when using serial in 28x1s and 40x1s - especially when trying to conserve precious ouput pins.
 

jsch2603

New Member
Thank you! I believe I now have all the bases (comm options) covered... Just a matter of determining the most practical approach now with what I have.
cheers ;)
 

jacobbiljo

New Member
I was interested in completing a similiar large led count project but after reading the Nuts and Volts article on various microcontroller's speeds i was worried about the how many cycles per second a picaxe could output. Altough jsch2603 stated he wasnt concerned about speed, does anyone have a rough idea about how many times per second a picaxe could output 16 states via I2C IO expanders or much cheaper shift registers?
 
Last edited:

hippy

Technical Support
Staff member
@ jacobbiljo : It's hard to give any exact figures.

In terms of transfer of control data the update rate could be quite high. If we say 50uS to bang out a byte of SPI we're looking at a theoretical 20,000 updates per second and that should be achieveable with PICAXE on-chip hardware.

The overhead comes in PICAXE processing time to execute the commands to initiate the output but even more so in what processing has to be done to determine the data to send. And of course how much data is sent and processed plays a big part and can cut update rates drastically.

Slow update rates are not always a problem. If you need to update a whole lot of things very frequently or near simultaneously it's a problem but many things don't need to be updated so frequently. It comes down to what any particular large LED project needs to do to say if a PICAXE or anything else is suitable or not.
 

jacobbiljo

New Member
Thanks ya i was hoping to use a picaxe to create a 4x4x4 cube with animations inside it by cycling through premade 16bit values. I wanted to try and stick with picaxe because I have programming and prototyping boards premade as well as previous experience and this project isnt valuable enough to me to justify learning another language. Using a 40X2 set as fast as possible which would read from eeprom and then write the values to the outputs do you think a POV project is doable, considering i would have to write 16 values, turn on another output to power the row then write 16 more, doing this 4 times per cycle.
Ive been leary to test this because its a big investment in leds and other chips for a project that might just look pathetic because it runs too slow to create a decent image.
 

BCJKiwi

Senior Member
If a 16 port I/O expander (e.g. MCP 23017) was used for each face then 6 would be required to produce the 6 faces of the cube.

Grabbing 6 words from wherever they are stored and writing them to the 6 I/O expanders via the i2c bus would be pretty quick. MCP23017 and other similar chips will run at a 400kHz bus speed.

The slow part would be working out which 6 words are needed from store and fetching them.

Suggest you write some code to work out the program requirements to get an idea of how it will be done and to refine the code for speed and size. Then once it is simulated you could go on to buying some hardware if you think it will be fast enough.

Note that i2c will not run in the simulator as there is no dummy for the i2c bus.
 
Last edited:

MBrej

Member
Look at the MAX6952 and MAX6953, they can drive 140 LEDs each, either through 26MHz SPI or I2C. They are ment to drive LED matrix displays and so have an ASCII 104 character font, but you can set any of the 140 LEDs to turn on or off individually. You can free sample the ICs so you can experiment without spending any more money :). I would have thought a 26MHz SPI interface would be fast enough, but the weak link will be the PICAXE on the speed front.

Matt
 

westaust55

Moderator
If you decide to run with I/O expanders would suggest the MCP23017 rather than the MCP23016, faster, simpler board layout and a few other enhancements.
Working examples of code in the misc projects section.
Ah, I had based my suggestion of the 23016 on BCJKiwi's comments in thread:
http://www.picaxeforum.co.uk/showthread.php?t=8098&highlight=23017
Where it was stated:
The configuration of a 23017 is different and more complex
[/quote

Had a look at the two 23016 and 23017 and agree the pin/signal layout of the 23017 is better. As a side issue I have thus added the 23017 to my components library for DIPTRACE as well for use by others (See:
http://www.picaxeforum.co.uk/showthread.php?t=10576).
 

westaust55

Moderator
Note that i2c will not run in the simulator as there is no dummy for the i2c bus.
The Programming Editor does have i2c simulation, but it is limited to the DS1307 (on i2c) and either a 24C16 or 24C256 EEPROM.

So yes, cannot simulate operation of any i2c IO expander

By way of example, the following example will work in the simulator (provided the Simulation options are set correctly and selecting the 28X1):
Code:
hi2csetup i2cmaster, %10100000, i2cfast, i2cbyte
hi2cout 0, ($01, $02, $03, $04, $05, $06, $07, $08)
pause 1000
hi2cin 0, (b0, b1, b2, b3, b4, b5, b6, b7)

serout 7, N2400, (#b0,CR, #b1,CR, #b2,CR, #b3,CR, #b4,CR, #b5,CR,
 
Last edited:

jsch2603

New Member
i2c is also quite easy for expanding...

Master
Code:
hi2csetup i2cmaster, %10100000, i2cslow, i2cbyte
main:
hi2cout [%10100000],0,(newvalue1)  'write value to slave 1
hi2cout [%10110000],0,(newvalue2)  'write value to slave 2
hi2cout [%11000000],0,(newvalue3)  'write value to slave 3
etc....
goto main
Slave1
Code:
hi2csetup i2cslave, %10100000
main:
get 0,(b1)
let outpins = b1
goto main
Slave2
Code:
hi2csetup i2cslave, %10110000
main:
get 0,(b1)
let outpins = b1
goto main
Slave3
Code:
hi2csetup i2cslave, %11000000
main:
get 0,(b1)
let outpins = b1
goto main
etc....
Thank you for your post(s). With regard to the original issue posted under this title, for the moment, I've proceeded to experiment with the I2C option as the method for communicating betwen my (3) 40X1's somewhat successfully (as impractical as this may seem) and have a few more follow-up questions as a result:

1. In both the Master and Slave 1 code provided above, I've noted that the slaveaddress used (%10100000) is the same for both. Might this be for the situation where the Master 40X1 would have its outputs redirected to the Slave 1 40X1, or perhaps just a "typo" in which case each should be unique (i.e. the Master with it's own and the Slave with its own slaveaddress)?
Configuration Note: I had envisioned utilizing the portb and c outputs of the Master for local Blue LED control; the Slave 1 ports b and c for Green LED control (via I2C); and Slave 2 ports b and c for Amber and Red LED control respectively (via I2c).

2. In the I2C setup code excerpt for the the Master 40X1 that follows, note that I have attempted to assign an output value to portc of Slave 1, via the hi2cout [%10110000],8,(grn_portc) command line. Early indications appear that this may not be possible and perhaps is another limitation of portc use. Can you please advise whether this is the case or not?
If so, it would appear as though using I/O expander chips would perhaps be the logical alternative at this point as pointed out.

Note: All control code has been consolidated to the Master 40X1

Master 40X1 i2c Setup
Code:
;BOARD #1 (40X1-1 Master) - BLUE, GREEN, AMBER/RED LED CONTROL

symbol LEDBLU_G00 = 0 					; rename output0 ‘LEDBLU_G00’
symbol LEDBLU_G01 = 1 					; rename output1 ‘LEDBLU_G01’
symbol LEDBLU_G02 = 2 					; rename output2 ‘LEDBLU_G02’
symbol LEDBLU_G03 = 3 					; rename output3 ‘LEDBLU_G03’
symbol LEDBLU_G04 = 4 					; rename output4 ‘LEDBLU_G04’
symbol LEDBLU_G05 = 5 					; rename output5 ‘LEDBLU_G05’
symbol LEDBLU_G06 = 6 					; rename output6 ‘LEDBLU_G06’
symbol LEDBLU_G07 = 7 					; rename output7 ‘LEDBLU_G07’

let dirsc = %11100111					; direct the (3) portc LSBs and MSBs as outputs’

symbol LEDBLU_G08 = 8	 				; rename output8 ‘LEDBLU_G08’
symbol LEDBLU_G09 = 9					; rename output9 ‘LEDBLU_G09’
symbol LEDBLU_G10 = 10 					; rename output10 ‘LEDBLU_G10’
symbol I2C_SCL_1 = 11 					; rename output11 ‘I2C_SCL_1’
symbol I2C_SDA_1 = 12 					; rename output12 ‘I2C_SDA_1’
symbol SPARE1_3 = 13 					; rename output13 ‘SPARE1_3’
symbol SPARE1_4 = 14 					; rename output14 ‘SPARE1_4’
symbol SPARE1_5 = 15 					; rename output15 ‘SPARE1_5’

;symbol SESS_END = porta pin0				; rename porta input pin0 ‘SESS_END’ (can't rename porta pins?)
;symbol SESS_RESET = porta pin1			; rename porta input pin1 ‘SESS_RESET’ (can't rename porta pins?)

symbol POWER_ON = pin0					; rename portd input pin0 ‘POWER_ON’
symbol AIR_PRS_LOW = pin1				; rename portd input pin1 ‘AIR_PRS_LOW’
symbol SYS_RESET = pin2					; rename portd input pin2 ‘SYS_RESET’
symbol MAT_OffD = pin3					; rename portd input pin3 ‘MAT_OffD’
symbol COWARD_CPUBATT = pin4				; rename portd input pin4 ‘COWARD_CPUBATT’
symbol FAULT = pin5					; rename portd input pin5 ‘FAULT’
symbol HIT = pin6						; rename portd input pin6 ‘HIT’
symbol FIRE = pin7					; rename portd input pin7 ‘FIRE’

symbol grn_portb = b0					; rename output variable b0 ‘grn_portb’ (slave 1, portb)
symbol grn_portc = b1					; rename output variable b1 ‘grn_portc’ (slave 1, portc)
symbol amb_portb = b2					; rename output variable b2 ‘amb_portb’ (slave 2, portb)
symbol red_portc = b3					; rename output variable b3 ‘red_portc’ (slave 2, portc)

symbol hit_counter = b10 				; define a ‘hit_counter‘ using variable b10
symbol fire_counter = b11 				; define a ‘fire_counter‘ using variable b11
symbol sr_counter = b12	 				; define a ‘sr_counter‘ using variable b12
symbol sr_value = b13					; define   ‘sr_value‘ (constant) using variable b13

hi2csetup i2cmaster, %10100000, i2cslow, i2cbyte; HI2CSETUP I2CMASTER, slaveaddress, mode, addresslen
								; - SLAVEADDRESS is the i2c slave address
								; - MODE is the keyword i2cfast (1MHz) i2cmedium (400kHz) or
								;   i2cslow (100kHz)
								; - ADDRESSLEN is the keyword i2cbyte or i2cword
								;   Note that this is the ‘addressing method’ used by the
								;   i2c device (i.e. some eeproms use a byte address,
								;   some use a word address). It is NOT the length of data
								;   returned by the hi2cin command, which is always a byte.

main:								; make a label called ‘main’

;setint %00001100,%00001100				; activate interrupt when pin2 and pin3 go high
								; NOTE: Is this location correct? I have seen program
								; examples with the setint located before the main loop
								; (i.e. in the setup area)

						; {HI2COUT [newslave],location,(variable,...)}
hi2cout [%10110000],0,(grn_portb)	; write output value grn_portb (b0) to slave 1 portb, sp register 0
hi2cout [%10110000],8,(grn_portc)	; write output value grn_portc (b1) to slave 1 portc, sp register 8 ?
hi2cout [%11000000],0,(amb_portb)	; write output value amb_portb (b2) to slave 2 portb, sp register 0
hi2cout [%11000000],8,(red_portc)	; write output value red_portc (b3) to slave 2 portc, sp register 8 ?
						; - LOCATION is a variable/constant specifying a byte or word address.
						; - VARIABLE(s) contains the data byte(s) to be written.
						; - NEWSLAVE is an optional new slave address for this (and all future)
						;   commands.

;START BLUE LED MAIN LOOP CONTROL --------------------------------------------
Slave1 40X1 i2c Setup
Code:
;BOARD #2 (40X1-2 Slave)

#REM
symbol LEDGRN_G00 = 0 					; rename output0 ‘LEDGRN_G00’
symbol LEDGRN_G01 = 1 					; rename output1 ‘LEDGRN_G01’
symbol LEDGRN_G02 = 2 					; rename output2 ‘LEDGRN_G02’
symbol LEDGRN_G03 = 3 					; rename output3 ‘LEDGRN_G03’
symbol LEDGRN_G04 = 4 					; rename output4 ‘LEDGRN_G04’
symbol LEDGRN_G05 = 5 					; rename output5 ‘LEDGRN_G05’ System Reset ind.
symbol LEDGRN_G06 = 6 					; rename output6 ‘LEDGRN_G06’
symbol LEDGRN_G07 = 7 					; rename output7 ‘LEDGRN_G07’

symbol LEDGRN_G08 = 8	 				; rename output8 ‘LEDGRN_G08’
symbol LEDGRN_G09 = 9					; rename output9 ‘LEDGRN_G09’
symbol LEDGRN_G10 = 10 					; rename output10 ‘LEDGRN_G10’
symbol I2C_SCL_2 = 11 					; rename output11 ‘I2C_SCL_2’
symbol I2C_SDA_2 = 12 					; rename output12 ‘I2C_SDA_2’
symbol SPARE2_3 = 13 					; rename output13 ‘SPARE2_3’
symbol SPARE2_4 = 14 					; rename output14 ‘SPARE2_4’
symbol SPARE2_5 = 15					; rename output15 ‘SPARE2_5’
#ENDREM


let dirsc = %11100000					; direct the (3) portc MSBs as outputs’

hi2csetup i2cslave, %10110000				; HI2CSETUP I2CSLAVE, slaveaddress
								; - SLAVEADDRESS is the i2c slave address

main:								; make a label called ‘main’

	get 0,outpins					; read data from the microcontroller scratchpad (sp) register 0
								; (IOW: get value of sp register 0 and put into variable b0)
;	let outpins = b0					; assign portb output byte value to variable b0
	
	get 8,b1						; read data from the microcontroller scratchpad (sp) register 8
								; (IOW: get value of sp register 8 and put into variable b1)
	let pinsc = b1					; assign portc output byte value to variable b1
	

; NOTE: Not clear on the purpose of the following code taken from Manual II (p50) and if it's to be located
; in the Master's code or the Slave's, if at all needed in this case.

;	if hi2cflag = 0 then main 			; poll flag
;	hi2cflag = 0 					; reset flag
;	get hi2clast,b? 					; get last byte written
;	let outpins = b?					; set output pins

	goto main
3. I could use a bit more insight on proper assignment of the "Location" (scratchpad register?) value for this application. Assuming I could send an output value via I2C to the Slave's portc, it would seem that this value would need to be different from that configured for portb in order to avoid conflict?

4. In the program code for the Slave, again assuming portc can be written to via the I2C bus, would it be necessary/permissable to configure portc using the "let dirsc = %11100111" command string?
It states in Manual II (p50) under hi2csetup - Slave Mode, Description, that "When in Slave Mode, all i2c functions of the slave PICAXE chip are automatic." Might this also mean that the above command string would not be necessary, assuming portc can in fact be utilized, of course?

5. In the subsequent example that follows on this same page (p50) of Manual II, I am uncertain if I should be including this code or not, and if it would be located in the main program of the Master or of the Slave?

Code:
if hi2cflag = 0 then main 			; poll flag
	hi2cflag = 0 			; reset flag
	get hi2clast,b? 			; get last byte written
	let outpins = b?			; set output pins
6. Lastly, is it not possible to rename the porta inputs (which I am utilizing as digital) with the "symbol" command?
I have attempted as can be seen, but have commented these lines out as a result of the syntax not being accepted.

Thank you again for your time and insights
 
Last edited:

BCJKiwi

Senior Member
Re 1. above'
Each i2c device must have a unique address.
in the case of 3 devices, all Picaxe, one is the master and two are slaves.

So when sending i2c data to the two slaves, the part in the square brackets
e.g. in hi2cout [%10110000],0,(newvalue2) the [%10110000] is the address of the slave to be written to.

Each time you change device to read or write to you must include the address. If you are continuing with the same device, then the part in [ ] can be omitted.

See Westy's reply below.
3. Scratchpad.
Scratchpad is a range of addresses from 0 through 127 (X1). By default, writing will start at zero. There is a pointer which will increment automatically so the next write happens at the next address.
to manage this process, use the ptr command prior to anything that puts data into, or when you want to read from, the scratchpad.
Read up on the Variable - scratchpad Manual2 page 11 of the current Manual.

Not sure about the rest. Experimetation may be the best answer on some of these - go with what works - you may be breaking new ground with some of these issues - just document it all for those who follow!
 
Last edited:

westaust55

Moderator
Some further explansion on the code offered by Techncial:

Master

Code:
hi2csetup i2cmaster, %10100000, i2cslow, i2cbyte
main:
hi2cout [%10100000],0,(newvalue1)  'write value to slave 1
hi2cout [%10110000],0,(newvalue2)  'write value to slave 2
hi2cout [%11000000],0,(newvalue3)  'write value to slave 3
etc....
goto main
For the master code example given by Technical, each HI2COUT command is writing to a different slave device. See the note by technical at the end of each line.

For the HI2COUT command the format is:
hi2cout [slave device address], slave memory/register location for first byte, (databyte1, databyte2, etc)

As BCJKiwi states, if you do several writes to the same slave device, the part [slave device address] could be omitted.

If the slave memory/register location for first byte is ommitted, then writing will be to the first location the the slave device scratchpad/registers




Ref your item 2:
Not sure that I fully gather what you are trying to do with portC on the slave devices.
But be aware that pins 3 and 4 of Port C on the PICAXE 40X1 are used for the i2c comms and thus not available as part of an 8-bit port for LED control
 
Last edited:

westaust55

Moderator
More on PortA and PortC use

Ports A and C are relatively limited in the way they can be used.

For PortC you can use the commands:

High PortC x ; where x is 0 to 7
Low Port C x ; where x is 0 to 7

But again, please realise that PortC pins 3 and 4 are used by the i2c comms connections.


PortA is even more restrictive and it is in BASIC only possible to test the state of these pins as inputs.

From the Manual Section 1:

Using porta as digital inputs
The porta pins 0 to 3 (legs 2 to 5) are, by default, configured as analogue inputs.
However they can also be used as simple digital inputs.
The following syntax is used to test the input condition:
if porta pin0 = 1 then jump
i.e. the additional keyword ‘portA’ is inserted after the ‘if’ command.
to test if two (or more) porta inputs are on
if porta pin0 = 1 AND pin1 = 1 then jump
to test if either of two (or more) porta inputs are on
if porta pin0 = 1 OR pin1 = 1 then jump
Note the portA command is only required once after the ‘if’ command.
It is not possible to test inputs on two different ports within the same if…then statement.
It is not possible to access the portA pins with any other ‘input’ type commands (count, pulsin etc). Therefore these pins should be reserved as simple on/off switches.​

I do not believe that you can use the SYMBOL command to assign alias names to port A or Port C pins.
 
Last edited:

westaust55

Moderator
4. In the program code for the Slave, again assuming portc can be written to via the I2C bus, would it be necessary/permissable to configure portc using the "let dirsc = %11100111" command string?
It states in Manual II (p50) under hi2csetup - Slave Mode, Description, that "When in Slave Mode, all i2c functions of the slave PICAXE chip are automatic." Might this also mean that the above command string would not be necessary, assuming portc can in fact be utilized, of course?

5. In the subsequent example that follows on this same page (p50) of Manual II, I am uncertain if I should be including this code or not, and if it would be located in the main program of the Master or of the Slave?


Code:
if hi2cflag = 0 then main 			; poll flag
	hi2cflag = 0 			; reset flag
	get hi2clast,b? 			; get last byte written
	let outpins = b?			; set output pins
6. Lastly, is it not possible to rename the porta inputs (which I am utilizing as digital) with the "symbol" command?
I have attempted as can be seen, but have commented these lines out as a result of the syntax not being accepted.

Thank you again for your time and insights

In your slave 40X1 code you have references to “Getting” values form scratchpad location 0 and separately to location 8.

How useful the example code you reference from manual 2 , will depend on how many bytes of data you are sending.

The first two lines will always be useful in terms of letting you know when new data has been written.

If you have a fixed number of bytes that you will write to and these would be pre-allocated functions for each byte then the slave 40X1 devices could look for the flag indicating new values then just action the entire block of code which sues those set of values.

If you have a block of bytes being used in the scratchpad and the master only changes one in any write function, then the line
get hi2clast,b1
will be useful to know where a change has occurred and then you could act just on the latest information.

It is really up to you how you wish to use the code sample given.
Without spending a lot of time analysing your entire code (which I do not have the time to do) unless you give more specific details of how many bytes you will write from Master to each Slave and how inter-related they are, we can only give general advise.
 

jsch2603

New Member
Gentlemen (& Ladies).

I'm sorry to be a bother on these issues, but I'm afraid that I find myself a bit "terminologically challenged" with some of the technical lingo at this point, and the manuals seem to be a bit lax in detail and examples (particularly for what I'm attempting to do; which may be quite unorthodox, but I would think it to be quite simple. Perhaps this is in some ways "breaking new ground" as mentioned. Nonetheless, I certainly appreciate all of your feedback.

Please let me attempt to summarize my questions for which I can find no clear resolve in studying manual 2, for the most part, and also attempt to clarify my application, current setup code and results...

Re:
Q1. I think I understand for the most part what is said in your posts, but am mainly questioning (in "Technical"s post) why the slaveaddress given in the Master's hi2csetup string is the same as that in the Master's first hi2cout string as bolded below:

Code:
hi2csetup i2cmaster, [B]%10100000[/B], i2cslow, i2cbyte
main:
hi2cout [B][%10100000],[/B]0,(newvalue1)  'write value to slave 1
Should these not be different? Because when I set them the same as shown, the (newvalue) does not get written to Slave1 (assuming the like address is setup @ Slave1). If I change the hi2cout slaveaddress to something like %10110000 (and likewise @ Slave1), then the newvalue writes to Slave1 portb output port as directed.

Re:
Q2. Ok, I will try to further clarify my configuration for the three (3) 40X1's connected via I2C: The first (the Master's) outputs will drive (11) Blue LED channels with (8) being assigned to portb and the remaining (3) assigned to portc. In doing so I have let dirsc = %11100111, where the SCL and SDA port bits (3&4) have been been left configured as inputs (0's).
First, I'm not sure if this is totally acceptable: to utilize the IC2 and configure portc like this. I am aware of the limits of portc as the manual and various posts state but have not seen anything that addresses configuring some as outputs whilst using the I2C bus.

Now, for Slave1: At the Master I have proposed the string:
Code:
hi2cout [%10110000],8,(grn_portc)	; write output value grn_portc (b1) to slave 1 portc, sp register 8 ?
The Slave1 outputs will be utilized similar to the Master's in that there will be (11) Green LED channels with (8) being assigned to portb and the remaining (3) assigned to portc.

The Slave1 setup code has been tried as follows:
Code:
let dirsc = %11100000		; direct the (3) portc MSBs as outputs’  (Again, It is not clear if this is permissable)

hi2csetup i2cslave, %10110000	; HI2CSETUP I2CSLAVE, slaveaddress

main:				; make a label called ‘main’
	get 0,outpins		; read data from the microcontroller scratchpad (sp) register 0    (THIS WORKS)
				; (IOW: get value of sp register 0 and put into variable b0)
;	let outpins = b0		; assign portb output byte value to variable b0    (THIS WORKS)
	
	get 8,b1			; read data from the microcontroller scratchpad (sp) register 8    (THIS DOESN'T WORK AS WRITTEN)
				; (IOW: get value of sp register 8 and put into variable b1)
	let pinsc = b1		; assign portc output byte value to variable b1       (THIS DOESN'T WORK AS WRITTEN)
With the last (2) strings above, I am trying to direct the contents of variable b1 to portc of Slave1 but I have not had any luck in doing this so far.

I would like to do approximately the same with the Slave2 40X1 by assigning (7) Amber Channels to portb and (7) Red Channel's (LEDs) to portc but portc has been a problem in both cases so far. There is no problem in sending the variable data to portb of Slave1 however at this time.

Appears switching to 16 port I/O expanders (e.g. MCP 23016/17) is looking better with time. Following a bit more experimentation I will post some preliminary conclusions on this matter. Thanks all for your help!
 
Last edited:

BCJKiwi

Senior Member
Q1,
The hi2csetup command for the master is dual function - it sets that device to be the master, AND tells the master which slave to talk to.
"HI2CSETUP I2CMASTER, slaveaddress, mode, addresslen"
The address is for the slave, not the master. The master does not need an address because it is the master and nothing is sent to it.
If there is only one slave, then no more device addresses need to be used anywhere in the program.

Q2 and Q3,
Initially for testing I would not use dirsc but high 0,1,2,5,6,7
This way you can test and get everything working. Then you could try dirsc - if it does not stuff up i2c then you are OK, if it does then just use the high method.
 

westaust55

Moderator
Q1 To give you an analogy on addressing:

You want to sent a letter to your friend by snail mail (post).
When you write the address, you put your friends address on the letter in you hand so that the postman will know where to deliver it.

For the PICAXE is it the same.
The Master is told the address of the Slave device in the HI2CSETUP command so it knows where to send the information. The Slave looks at the i2c bus and only accepts information with its specific address.
 
Last edited:

jsch2603

New Member
That's good; now to continue with that analogy...

For starters, I understand then that I have a slave 1 (40X1) with the hypothetical address %1010000 which is addressed in the

hi2csetup i2cmaster, %10100000, i2cslow, i2cbyte

string of the Master's setup code... I'm with you on that.

I understand that the first

hi2cout [%10100000],0,(newvalue1) 'write value to slave 1

command string in the Master's main loop is used then to send newvalue1 to Slave1, ok....

Now, if I add Slave 2 (40X1) to the mix, I understand that the

hi2cout [%10110000],0,(newvalue2) 'write value to slave 2

will direct newvalue2 to Slave 2 because of the different slaveaddress [%10110000] identified in this string.

My fundamental question is then: If the Master's setup string

hi2csetup i2cmaster, %10100000, i2cslow, i2cbyte

has only the address %10100000 for Slave 1, how is Slave 2's slaveaddress accounted for in this setup string?

The analogy as I see it for this would be:

I have a letter addressed to Slave 1 (%10100000) in the Master's setup string, ok, understood; I also now want to send a letter to Slave 2 (%10110000), but this address is not listed in the Master's setup string.

Why then is it not required for Slave 2's address to be in the Master's setup string as well? Does it only need the first Slave's address and then assume that %10110000 (Slave 2's address) is next in line? I'm not sure how else to ask this. This I question before the

hi2cout [%10110000],0,(newvalue2) 'write value to slave 2

which I understand the purpose of.

Whew, I hope this question makes sense. Thanks again.
 

hippy

Technical Support
Staff member
@ sch2603 : The address in the HI2CSETUP is not important in this example because you are specifying which slave you are addressing in your HI2COUT commands, whichever address is used then supersedes whatever was specified in the HI2CSETUP command.
 

westaust55

Moderator
For the HI2CSETUP command, this sets up the i2c comms for a specific type of slave device.
In your case other PICAXE chips.

While you are only addressing other devices of the same time you do not need to keep using the HI2CSETUP command for each one.

But if you get more complex (later on) and start also addressing say EEPROM or IO Expanders then each time you first wish to communicate with a different device type you must issue a new HI2CSETUP command.

As Hippy has stated, while using the same type of device as referenced in the (last) HI2CSETUP command you can just add the optional Slave Address to the HI2COUT command to access another like device.
 

jsch2603

New Member
Thank you both... That is exactly the clarification I was looking for at this time. Meanwhile, back to fiddling with the Slave portc's, but I have a feeling I will not be able to address (write to) these from the Master. BCJKiwi, I will give your alternative configuration suggestion for the Slave portc's a go. I still am not sure if any configuration of the Slave portc's can be done at the slave as was successfully done at the Master in my case; let alone the question as to whether such configuration of the Slave portc's can co-exist with (work in tandem) with the I2C bus. Thank you
Cheers
 
Last edited:

jsch2603

New Member
.
But be aware that pins 3 and 4 of Port C on the PICAXE 40X1 are used for the i2c comms and thus not available as part of an 8-bit port for LED control
Ahhh yes, but are the remaining 6-bits of said portc available to be configured as outputs on a 40X1 when setup as a slave device utilizing i2c, is the question ;)
 

jsch2603

New Member
In your slave 40X1 code you have references to “Getting” values form scratchpad location 0 and separately to location 8.

How useful the example code you reference from manual 2, page 50, will depend on how many bytes of data you are sending.

The first two lines will always be useful in terms of letting you know when new data has been written.

If you have a fixed number of bytes that you will write to and these would be pre-allocated functions for each byte then the slave 40X1 devices could look for the flag indicating new values then just action the entire block of code which sues those set of values.

If you have a block of bytes being used in the scratchpad and the master only changes one in any write function, then the line
get hi2clast,b1
will be useful to know where a change has occurred and then you could act just on the latest information.

It is really up to you how you wish to use the code sample given.
Without spending a lot of time analysing your entire code (which I do not have the time to do) unless you give more specific details of how many bytes you will write from Master to each Slave and how inter-related they are, we can only give general advise.
I used an initial scratchpad value of 8 anticipating that I could write a byte of data to portc so as not to conflict with the byte being written to portb which I assigned to sp register 0. I don't know if this if proper usage at this time but it made some sense initially based upon my limited knowledge / use of scratchpad memory to date.

Overall, my application is quite straight forward. The best I can answer your concern at this time is that I will be writing a single byte of data to portb on the master as well to both slaves (but the byte is often varying in value, sometimes all bits on, sometimes sequencing, sometimes 1-bit on, etc.) The same is true for all portc's, whether it be the master or slave 40X1, but only the (3) LSB outputs of both the master and slave1 portc's (3-bits) will be used (are needed), and all of the available portc outputs of slave2 will be used (less of course the (2) used for i2c comm), again, if this found to be possible. I don't know if this makes anything clearer short of supplying the code which I do not want to burden one with, although output pin assignments can be readily discerned from the setup (symbol) code and the program can be copied and run with the simulator quite readily to display I/O usage. Both I and O are documented (renamed) for enhanced clarification. I really don't want to waste more of anyones time than I have to with this; and pending a bit more experimentation, perhaps I will simply bite-the-bullet and proceed to incorporate I/O expanders into the design instead. However, I'm sure that these come with their own set of configuration issues as well.

I will need to study up further on the above code example interpretation that you have provided. Thank you again for your continuing assist.
 

westaust55

Moderator
Ahhh yes, but are the remaining 6-bits of said portc available to be configured as outputs on a 40X1 when setup as a slave device utilizing i2c, is the question ;)
This is not something I have tried myself. My thoughts are in line with what BCJKiwi has already stated.

So while assumptions can get one into trouble, in the absence of written documentation within the manuals, here goes:

Using the DIRSC command operates on all 8 bits of port C and is likley to disrupt the i2c comms, particularly if that has already been established.

If the PICAXE inbuilt interpreter operates as one might expect (hope), using commands like HIGH PORTC 1 and LOW PORTC 1 by default only change that PORTC pin to an output and should not affect the i2c comms on PORTC pins 3 and 4.

So, the above having been said (assumed), barring clarification or confirmation by Technical, I suggest that you do some experiments and see if the HIGH PORTC x (x = 0 to 2 in your case) works while maintaining i2c comms.

You may be breaking some new ground here that ultimately could be useful to others, so document what you do and let all know how it performed later.
 

hippy

Technical Support
Staff member
If DIRSC does affect I2C ( no idea if it does, easy enough to test ) then setting or clearing the relevent bits for the pins used by I2C before setting DIRSC should prevent any problems.
 

tarzan

Senior Member
i2c slave portc

i2c master
Code:
#picaxe 40X1 'tested on A.3
#terminal 4800
setfreq em4
HI2CSETUP I2CMaster, %10100000, i2cslow, i2cbyte
pause 1000
main:
for b0 = 0 to 255
hi2cout b0,(b0)
sertxd (#b0,13,10)
pause 500
next b0
goto main
i2c slave portc
Code:
#picaxe 40X1 'tested on A.3
#terminal 4800
setfreq em4
dirsc = %11100111
pinsc = %00000000
HI2CSETUP I2CSLAVE, %10100000
ptr = 0
setintflags %01000000,%01000000
main:
pause 2000
goto main
interrupt:
get hi2clast,b0
if bit3 = 1 then gosub error
if bit4 = 1 then gosub error
pinsc = b0
hi2cflag = 0
setintflags %01000000,%01000000
return
error:
sertxd ("*** ERROR ***",13,10,"DO NOT SEND NUMBER: ",#hi2clast,13,10)
bit3 = 0
bit4 = 0
return
 
Last edited:

jsch2603

New Member
Ureka!?

Good day all,

This morning before having read any of your most recent posts, I quickly tried BCJkiwi's earlier suggestion of configuring the slave's portc using:

high portc 0,1,2,5,6,7 (i.e. %11100111) Correction: This was originally posted as portc high 1,2,3,5,6,7 by mistake in haste.
Thank you lbenson for pointing that out in a follow-up post.

as opposed to:
let dirsc = %11100111

This adjustment has apparently resolved a problem in that I can now gain control over portc outputs on the slave... Thank's much BCJ!

Note: Per Tarzan's example that follows, I have now switched to these initialization strings instead, at the slave:
let dirsc = %11100111
let pinsc = %00000000

This initialization also appears to work and has allowed me to gain control over the slave portc as well whilst using i2c. However, I don't want to mislead, and must caution that more conclusive testing and investigation is being conducted as it applies to my application, so my findings are still somewhat inconclusive at this point and I will continue to update this post as necessary.


Now that I have had a chance to read all of your most recent posts, I find that you are all right-on with your assessments:

Westy: you have hit the nail directly on the head it appears, thank you!

Hippy: your reinforcement on this issue has been most helpful, thank you as well!

Tarzan: That's a little bit over my head at this stage, but I will study on the code (test results) that you have kindly provided. Thank you also!
[Update] I have recently run this code and it has revealed many helpful ideas in relation to some obstacles that I am now facing in getting my data to display properly on the slaves' outputs. Thanks much!

Please disregard the following paragraphs:
One interesting / curious note regarding portc configuration remains at this time however:
Note that I still am using the let dirsc = %11100111 command string in the Master's setup code without problem it would appear. Portc on the Master continues to operate just fine with this code and there seems to be no ill effect with regards to the i2c communication. However, I will point out that the response to a given input condition on the Master has a somewhat delayed response on my test Slave1 output condition. Perhaps this "let dirsc" statement is causing this effect, in which case I will now try the alternative method here as was applied to the Slave. If that doesn't work, more than likely I will need to incorporate an interrupt for that input condition. I need to verify the effect that pauses may be having in my code still.

Can anyone verify as to whether the initial interrupt string should be placed before or after the main loop header, in addition to being in located in the interrupt loop itself? I have seen sample code where is has been placed both before and after the "main" loop header and am not real clear on this from reading the manual. It did work fine when placed before the "main" label, but now having seen it placed after in a recent example has led to some confusion.


More results later. Cheers
 
Last edited:

westaust55

Moderator
Good day all,

Can anyone verify as to whether the initial interrupt string should be placed before or after the main loop header, in addition to being in located in the interrupt loop itself? I have seen sample code where is has been placed both before and after the "main" loop header and am not real clear on this from reading the manual. It did work fine when placed before the "main" label, but now having seen it placed after in a recent example has led to some confusion.

More results later. Cheers
You can put the SETINT command where ever it is needed.
If there are actions that need to be completed before your allow an interrupt then just do those first.

Labels like INIT: and MAIN: are just that, labels. You could use FIRST: and SECOND: or whatever.

INIT: infers initialisation of parameters, IO, etc, that need to be done once only before the main program starts.
 

lbenson

Senior Member
>portc high 1,2,3,5,6,7 (i.e. %11100111)

Is this from memory? As I read manual 2, to achieve your binary result you should have

high portc 0,1,2,5,6,7

I don't see that this command would imply that portc pins 3 and 4 would be low--is it true that they would just retain their previous state?
 

westaust55

Moderator
A couple of points arising out of the useful example that Tarzan has given:

1. The first line (if required) after the interrupt: label should be SETINTFLAGS OFF

2. The Manual 2 provides a series of notes at the end of the SETINT command section ,but no such notes for the SETINTFLAGS command.

2) When the interrupt occurs, the interrupt is permanently disabled. Therefore to
re-enable the interrupt (if desired) a SETINT command must be used within
the interrupt: sub-procedure itself. The interrupt will not be enabled until the
‘return’ command is executed.
3) If the interrupt is re-enabled and the interrupt condition is not cleared within
the sub-procedure, a second interrupt may occur immediately upon the return
command.
If the same notes are applicable, then based on note 2, the SETINTFLAGS OFF command is not required.

Maybe RevEd / technical can clarify whether the note do apply in which case a note at the end of the the SETINTFLAGS section referencing the SETINT notes would be a useful addition for the next manual update.
 
Top