i2c and setint/setintflags

dgc188

New Member
I can't help think I'm missing something here! And I probably should know better.

I'm trying to make use of the i2c protocol and am having trouble sending data out - receive onto the master is ok. One 4k7 pullup per i2c rail.

I have a 18M2 acting as the "master" reading a number of sensors; and one 28X2 and two 40X2 acting as "slaves". The 28X2 reads data on its input pins and sends it to the master (no problem). This data, together with more data read by the 18M2 is then combined and output to the two 40X2 devices - only it doesn't get received.

I was hoping to use the SETINT or SETINTFLAGS command to cause an interrupt only when new data needs to be read by the two 40X2's. Looking at the SETINT command, I can see a comment about SETINT input,mask,port - port being A,B,C,D - I am beginning to presume that this makes use of an otherwise spare input port (8 pins) on the 40X2's. No chance! No spare pins, all in use.

Just where does the "flag" byte come from? Does it arrive via the i2c data channel? or does it, using the SETINT command, as it might appear by checking the syntax checker, make use of a whole set of input pins? Totally confused!

On the master 18M2 - all chips running at 16Mhz:
hi2csetup i2cmaster, %10100000, i2cfast_16, i2cbyte
hi2cout 42,(b0,b1) ; question, where does the "42" here represent? scratchpad or standard bx variables? Surely it's pointing at a location on the receiving end

On the slave#1 40X2:
hi2csetup i2cslave, %10100000
setintflags %01000000,%01000000 ; or just setint
...code...
goto main
;
interrupt:
hi2cin 42,(b42,b43)
bptr=42 ; save in scratchpad 42,43
;Homesensorin=@bptrinc ; sensors1-8 (b42) - from master b0
get @bptr,homesensorin
inc bptr
;Homesensor2in=@bptr ; sensors (b43) - from master b1
get @bptr,homesensor2in ; both the above lines of code have been tried
hi2clast=0 ; reset pointer
hi2cflag=0 ; reset flag
setintflags %01000000,%01000000
return

I've tried not bothering with the interrupt: routine and just letting it receive data as part of the normal program (putting that code in the interrupt routing direct into the program listing) - nothing gets received, whether I use bptr or ptr as pointers to read the incoming data. Connections (SDA/SCL) have been checked and are good (and the right way round!).

Both 40X2's run a test/check program to test their own inputs/outputs and are fine.

Where am I going wrong? No doubt it's staring me in the face, but I just can't see it.

Thanks in advance......
 

inglewoodpete

Senior Member
The operation of the PICAXE i2c slave makes the job so easy. Once configured with i2c setup, it behaves like just about every i2c slave device: it waits for the master to place data in the slave's scratchpad (or read from it). This will set the hi2cFlag in the slave and all the slave has to do is read the data in its own scratchpad. You can have your main loop poll this flag for an indication of new data or configure the interrupt routine to respond to the flag. My preference is to use the polling method.
 

dgc188

New Member
Thank you Phil for the pointer to the thread. It just goes to prove the different ways of entering a search criteria, getting just the right wording to get the information needed. So thank you for that. I certainly missed that one! And thanks to Goeytex for the examples in the other thread. I shall try these examples later when time permits in the project room.

Also thanks to Pete; I also thought setting up i2c was simple and straight forward. Follow the examples in the manual and Bob's yer uncle; or maybe not, as I found.

It would seem the manual (Pt.2) has a fair bit of information missing, or not fully explained, on this subject of i2c. Or maybe it is and I've just not read/understood it correctly (most likely the problem!).

First off, there's no indication of the meaning/location criteria of the first figure in the hi2cout/hi2cin commands, in that - even here maybe I've got it wrong - that the data always goes to/from the scratchpad (not RAM or EEPROM) starting at address "0" - hence the "0" in the examples shown in the manual - or is that just for the examples? I had thought that this first number could be changed to get/put the data where it was wanted - I tried it to scratchpad 42 for example. HI2CIN/HI2COUT location,(variable,...) Location is a variable/constant specifying a byte or word address. Nothing relating to it must be scratchpad "0". Or have I again misunderstood and 42 is in fact valid?

I've also been using HI2CIN on the slave - maybe this has not been explained clearly enough that this is only relevant to the master - HI2COUT is specified for use on the master. Then there's the use of ptr and bptr (relating to scratchpad and normal Bx variables). This is where I think things have been going awry.

I've taken relative snippets of Goeytex's code combined together with my own bits of relevant code (as shown below) and I can now possibly see where corrections are needed.

So, it's back to the drawing board and taking the examples shown a little closer to heart and make use of ptr and bptr correctly as shown. I shall report back later once I've got it working (or not, as the case may be!).

Again, thanks to all for the info.


master
;
hi2csetup i2cmaster, %10100000, i2cfast_16, i2cbyte
main:
hi2cout 0,(b1,b2,b3,b4)
my code - hi2csetup i2cmaster, %10110000, i2cfast_16, i2cbyte ;40X2 #2
my code - hi2cout 42,(b2,b3)

Read_Data:
hi2cin 0,(b5,b6,b7,b8)

my working code - hi2csetup i2cmaster, %10101000, i2cfast_16, i2cbyte ;28X2
my working code - hi2cin 10,(b2,b3)


slave
;
hi2csetup i2cslave, %10100000
setintflags %01000000,%01000000
my code - init:
my code - hi2csetup i2cslave, %10110000 ;40X2 #2
my code - setint %01000000,%01000000

main:
pause 1000
;
goto main

interrupt:

bptr = 0
pause 10
for ptr = 0 to hi2clast
get ptr,@bptrinc ' get all received bytes starting at location 0
next ' and put them into variables B0 to Bx

DEBUG 'look at variables to confirm operation

pause 500
let hi2cflag = 0 'clear interrupt & reset
setintflags %01000000,%01000000
return 'to main

my code:
interrupt:
hi2cin 42,(b42,b43) ; not required? only for the master?
hi2cflag=0 ; reset flag
hi2clast=42
ptr=42
sensorsin=@ptrinc
sensors2in=@ptr
hi2clast=0
setintflags %01000000,%01000000
 

inglewoodpete

Senior Member
In the slave, commands like hi2cIn, hi2cOut (both Master-only commands) and Debug (stops the background i2c handler from working) should not be used. Carefull use a short SerTxd commands should be used when you have to check on what is happening.

As I said previously, the master either reads the chosen slave's addressed scratchpad locations or writes to these locations. Let's say that both Master and Slave software are both using Slave scratchpad locations 10, 11 and 12 for transfers slave-to-master and 13, 14 and 15 for transfers from master-to-slave. The slave will write ("Put" command) data it wants to send to the master be writing to its own scratchpad locations 10, 11 and 12. The master will use hi2cIn to read those locations in the slave. In the reverse direction, the master would write data into the slave's scratchpad locations 13, 14 and 15 with the hi2cOut command. The slave will read those three locations in its own scratchpad ("Get" command) to process the data from the master.

So the master only uses hi2cIn and hi2cOut commands once configured. And the slave only reads and writes to its own scratchpad with commands like Get, Put and @ptr.

Finally, the slave has 1024 bytes of scratchpad. So the master's setup command must use the i2cWord paramater, since the i2cByte parameter can only allow addressing of 256 locations in the slave.
 
Last edited:

inglewoodpete

Senior Member
The following demo code should work for your slave:
Rich (BB code):
#PICAXE 28X2
Symbol sensorsin  = b22
Symbol sensors2in = b23
'slave
;
hi2csetup i2cslave, %10100000        'or $A0
setintflags %01000000,%01000000
'my code - init:
'my code - hi2csetup i2cslave, %10110000 ;40X2 #2
'my code - setint %01000000,%01000000

main:
     pause 1000
     SerTxd(#b22, ", ", #b23, CR, LF) 'Much shorter interruption to background i2c operation
     ;
     'SerTxd(#sensorsin, ", ", #sensors2in, CR, LF) 'Alternate syntax for above command
goto main

interrupt:
       hi2cflag=0 ; reset flag
       'hi2clast=42         I don't know what this is for
       ptr=42
       sensorsin=@ptrinc
       sensors2in=@ptr
       'hi2clast=0          I don't know what this is for
       setintflags %01000000,%01000000
return               'Must return from Interrupt routine to work, otherwise program will terminate
 
Last edited:

hippy

Technical Support
Staff member
It would seem the manual (Pt.2) has a fair bit of information missing, or not fully explained, on this subject of i2c. Or maybe it is and I've just not read/understood it correctly (most likely the problem!).
It would generally be assumed that anyone using I2C would understand the basic concepts of using I2C, were familiar with accessing I2C devices, so would not be detailed in that section of the manual.. We do have a tutorial on I2C which may help - https://picaxe.com/docs/axe110_i2c.pdf

First off, there's no indication of the meaning/location criteria of the first figure in the hi2cout/hi2cin commands, in that - even here maybe I've got it wrong - that the data always goes to/from the scratchpad (not RAM or EEPROM) starting at address "0" - hence the "0" in the examples shown in the manual - or is that just for the examples?
Most I2C devices have an array of registers or memory., usually at address 0 upwards. The first value in the HI2C commands is that address. So "HI2CIN 4, (b0)" would read the value stored in location 4 of the I2C device, "HI2COUT 5, (123)" would write 123 to location 5 in the I2C device.

When a PICAXE is used as an I2C device, as an I2C Slave, its Scratchpad memory is the equivalent of that array of registers or memory. So "HI2COUT 5, (123)" would place 123 in location 5 of the PICAXE's Scratchpad.

The address of 0 used in the examples is somewhat arbitrary, could be anything. It is usually 0 because, no matter what locations are available in an I2C device, location 0 likely will be.

So basically, once your master has executed "HI2COUT 5, (123)", the PICAXE slave will find the value 123 has been placed in its Scratchpad at location 5. The 'hi2cflag' will get set, and interrupt if enabled, once that has occurred.

The transfer from the master to the slave is entirely transparent to the slave, save for 'hi2cflag' being set and potentially interrupting. The slave doesn't need to do anything to receive I2C data other than initialising itself as an I2C Slave. It is almost certainly using HI2CIN on the slave which is causing you problems.
 

hippy

Technical Support
Staff member
Finally, the slave has 1024 bytes of scratchpad. So the master's setup command must use the i2cWord paramater, since the i2cByte parameter can only allow addressing of 256 locations in the slave.
Though the Scratchpad has 1024 bytes, only the first 256 bytes are used as I2C accessible memory, and it behaves as a 256 byte addressable memory so the I2CWORD does not need to be used, would probably cause issues if it was.
 

dgc188

New Member
It would generally be assumed that anyone using I2C would understand the basic concepts of using I2C, were familiar with accessing I2C devices, so would not be detailed in that section of the manual..
Thanks guys for the notes and comments.

Specifically to hippy:
As I'm new to the concept of using i2c (other than it's a two-wire communication protocol/process and essentially transparaent to the processors involved) where else would I be looking for information other than in the manual that gives details of the commands, etc. especially where two (or more) PICAXE devices are acting as the slaves. Reading/writing to/from such as an EEPROM is something else - you write it, it essentially does nothing with it and you read it back; simple. Therefore, there should be no general assumption that anyone starting on the road to dealing with i2c would already know and understand the concepts of it when dealing with active slave devices - that's why there's a manual to get that information - or that's what I thought.

The previously read AXE110 document gives some informative detail and, by substituting the old read/write commands with the newer versions, some sense can be made of it. But the document deals with reading and writing to and from what are essentially dumb devices and nothing with regard to multiple active devices such as PICAXE processors, one of which is acting as the slave and is programmed for other things and needs to read the information sent to it by the master for its own use. As noted in my first post, I have been able to read information back into the master from the slave - that wasn't the problem; that side of i2c is documented and has worked accordingly. The problem was getting the PICAXE slave to read data sent to it from the master so that it can make use of that data - and this, in my mind, is where there is a bit of an informational shortfall in the manual. But thanks for the further notes and that makes things somewhat clearer.

Thanks Pete for the note on DEBUG and that it stops the i2c handler. I never knew that and that might also start to explain some aspects of the lack of my slave receive data. I used DEBUG on the slave to try to see what was happening. Also thanks to both Pete and hippy for noting (and confirming) that both HI2CIN and HI2COUT are "master" only commands, HI2CIN is not documented as such in the manual, whereas HI2COUT is; also that I can put data to any scratchpad location, as I had suspected, and not just loc "0" as in the examples shown again in the manual.

Some of these things are pretty basic, I would agree, but when something fails to work as expected, everything becomes suspect and clear information is needed as to where things are going wrong. Hopefully, now armed with all this additional knowledge, I can expect my next attack on the software will finally result in a working project.

However, I appreciate those that have contributed to my serious i2c learning curve and have documented a little more information and detail as to the how and why, etc. of i2c. With these notes in mind, I shall go away shortly and put that information into my code and see what happens.
 

dgc188

New Member
Thank you to one and all for the hints, pointers and the odd bit of code relating to my i2c comms issues, i.e partially not working.

I can now gratefully report that I have got my project up and running - at least in a basic form from which I can now build up the software further. I was having some confusion between using bptr and ptr as well as having a more basic "wiring" issue with SDA and SCL transposed between two of the four processors involved in the project (stupid mistake but it certainly added confusion into the mix! Initially, one pair of processors (slave to master) transmitted ok whilst the others failed to receive any master to slave transmitted data).

For the benefit of anyone else having the same/similar issues of getting their i2c comms to work.....
On the master (18M2) I am now using:

Code:
main:
hi2csetup i2cmaster, %10110000, i2cfast_16, i2cbyte
hi2cin 10,(b4)                ; get data from Terminus from scratchpad location 10 to b4
[code for other transfers, etc]
hi2csetup i2cmaster, %10100000, i2cfast_16, i2cbyte
hi2cout 42,(b0,b1)                    ; send data to Layout scratchpad 42 from b0, b1
and on the slave (40X2):
Code:
hi2csetup i2cslave, %10100000
main:
gosub interrupt
[code to sort the incoming data]
interrupt:
hi2cflag=0                     ; reset flag
ptr=42                    ; save scratchpad 42,43 into b42(homesensorin), 43(homesensor2in)
homesensorin=@ptrinc
homesensor2in=@ptr
;setintflags %01000000,%01000000    ; set interrupt for master "write"
return
Oh! and check the SDA/SCL wiring!! (I might as well admit my own failings!)

I have opted not to use the setintflags as the routine only needs to be called once per run-through of the code - and there were too many master outputs/(interrupts) and it was slowing the overall slave routine down unnecessarily. I still use the routine as "interrupt:" but simply called as a normal gosub call rather than an interrupt call. Does the same job but only when I feel it needs calling.

So, again, that to all for the advice.
 

inglewoodpete

Senior Member
Yes, that should work. I suggest you change the name of the subroutine to a name other than "interrupt". It is likely to cause you confusion in the future as you develop your PICAXE skills.
 
Top