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


Reply via email to