Thanks for this. I quick had a look, looks like mine, see attachments:
* sb_i2c_slave: a i2c hardware lib to init, read and write
* i2c_slave.jal: client code, extracted from a bigger file, so code isn't
functional, it's just for the structure.
Maybe we could transform it in a lib. See my file: in the ISR, it just call
the appropriate procedure according to the state. User code would be:
* define procedure for each tests
* include the lib
* use i2c_hw_slave_init() to set the slave's address
Of course, user has to know what all these states are about, but at least he
doesn't have to deal with masks, etc...
Seb
Le Sunday 14 December 2008 17:45:30 Joep Suijs, vous avez écrit :
> Hi Seb et al,
>
> You needed some patience, but enclosed my i2c slave sw.
> It does not qualify as a lib, since there is a section in the code
> that defines the i2c sequences it supports and that has to be adapted
> for each application. It gets info from global vars or put data from a
> message into vars.
> The lib has one major limitation: a written message is not processed
> until the next activity of this slave. This means you have to read at
> least one byte after you write a sequence...
>
> Joep
>
>
--
Sébastien LELONG
http://www.sirloon.net
http://sirbot.org
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"jallib" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/jallib?hl=en
-~----------~----~----~----~------~----~------~--~---
-- /!\ i2c pins (SDA and SCL) must have been configured as input
-- *before* including this file
var byte tmpbuf
procedure sb_i2c_init_slave(byte in height_bits_icaddress, bit in
start_stop_int) is
-- For testing purpose (checking if slave is responding to START/STOP
signals)
-- you may want to activate 7bits address with interrupts (see spec)
if start_stop_int
then
SSPCON1 = 0b_0011_1110 -- slave 7bit address, start/stop
interrupt
else
SSPCON1 = 0b_0011_0110 -- slave 7bit address
end if
-- I2C slave hardware
-- last 8th bits is for read/write setting.
-- I think it can be either 0 or 1, PIC does the job
SSPADD = height_bits_icaddress
-- init SSPSTAT
SSPSTAT_BF = false
SSPCON1_WCOL = false
SSPCON1_SSPOV = false
PIR1_SSPIF = false
-- enable interrupts
PIE1_SSPIE = true
INTCON_GIE = true
INTCON_PEIE = true
end procedure
function sb_read_i2c() return byte is
tmpbuf = SSPBUF
return tmpbuf
end function
procedure sb_write_i2c(byte in what) is
-- wait 'til buffer is empty
while SSPSTAT_BF loop end loop
var bit dosend = true
while dosend
loop
SSPCON1_WCOL = false
-- try to write into buffer, checking collision
SSPBUF = what
if ! SSPCON1_WCOL
then
-- ok, done
dosend = false
end if
-- else continue trying
end loop
SSPCON1_CKP = 1
end procedure
var byte tmpstat
-- init Slave i2c (from dcmc_config values)
-- no Start/Stop interrupts
sb_i2c_init_slave(I2C_SLAVE_ADDRESS,false)
procedure proceed_state_1() is
pragma inline
-- state 1:write operation, last byte is address, buffer full
-- byte is an address, it we get here, we just know master
-- wants to talk to us...
-- and we also know address is recognized (BF is set, see spec)
-- anyway, we must read buffer to reset BF bit
var byte _trash = sb_read_i2c()
data_led = high
end procedure
procedure proceed_state_2() is
pragma inline
-- state 2: write operation, last byte is data, buffer full
-- 2 possibilities:
-- * Master sent a action (eg. MAX_PWM_CHAR)
-- * Master sent a value to set
if ! got_motor
then
i2c_motor = sb_read_i2c()
-- normalize string'd motor values ("0", "1") to 0 or 1 bytes
i2c_motor = i2c_motor - "0"
got_motor = true
elsif ! got_action
then
action = sb_read_i2c()
got_action = true
elsif ! got_value
then
value = sb_read_i2c()
got_value = true
-- motor and action should be already set
-- Note: don't need to pass value, since "global" and
-- procedures in eval will do their job (GET or SET)
i2c_eval(i2c_motor,action)
-- done with this command
reset_state()
data_led = low
;;;else
;;; -- what to do ?
end if
end procedure
procedure proceed_state_3() is
pragma inline
-- state 3: read operation, last byte is address, buffer empty
-- master wants to get a value from us (ex: speed for motor 1)
-- Note: no value involved here, since it's a GET operation
-- Note again: no need to check motor or action, since
-- these are done via write op. and handled in state 2
-- Master is just waiting for incoming data
ready_led = low
i2c_eval(i2c_motor,action)
ready_led = high
end procedure
procedure proceed_state_4() is
pragma inline
-- state 4: read operation, last byte is data, buffer empty
-- master still wants to get a value from us
-- This should never occured, since only one byte is sent per request
while true
loop
delay_1ms(50)
ready_led = low
delay_1ms(50)
ready_led = high
end loop
end procedure
procedure proceed_state_5() is
pragma inline
-- state 5: nack
-- master doesn't want to talk with us anymore
-- reset slave logic
-- AN734 does not talk about setting CKP, whereas spec says
-- it must be set. Some people say it can be error prone.
-- So... well... just set it :), and reset state-machine'd values
reset_state()
SSPCON1_CKP = 1
data_led = low
end procedure
procedure proceed_error() is
pragma inline
-- something went wrong, that is, XOR operations did not match
-- SSPSTAT bits
-- Just log current status
forever loop
data_led = high
delay_1ms(100)
data_led = low
delay_1ms(100)
end loop
end procedure
procedure ssp_handler() is
-- This a "standard" implementation of a state-machine, following
-- instructions of Microchip AN734
pragma interrupt
if PIR1_SSPIF
then
-- Now reset interrupts (ie. enable next one)
PIR1_SSPIF = false
-- mask out unimportant bit
tmpstat = SSPSTAT
tmpstat = tmpstat & 0b_0010_1101
-- check state 1: write operation, last byte is address, buffer
full
if (tmpstat ^ 0b_0000_1001) == false
then
proceed_state_1()
-- check state 2: write operation, last byte is data, buffer
full
elsif (tmpstat ^ 0b_0010_1001) == false
then
proceed_state_2()
-- check state 3: read operation, last byte is address, buffer
empty
elsif (tmpstat ^ 0b_0000_1100) == false
then
proceed_state_3()
-- check state 4: read operation, last byte is data, buffer
empty
elsif (tmpstat ^ 0b_0010_1100) == false
then
proceed_state_4()
-- check state 5: nack
elsif (tmpstat ^ 0b_0010_1000) == false
then
proceed_state_5()
;;-- check only got a start signal (when using interrupts)
;;else
;; proceed_error()
end if
else
-- another interrupt. Weird...
proceed_error()
end if
end procedure