-- -- Description: Software implementation of I2C (single) master. -- -- -- -- Define i2c pins like: -- alias i2c_scl is pin_c3 -- alias i2c_scl_direction is pin_c3_direction -- alias i2c_sda is pin_c4 -- alias i2c_sda_direction is pin_c4_direction -- -- -- -- optional _i2c_scl_timeout to prevent system from hanging in a loop. -- const _i2c_scl_timeout = 100 -- units are in bit-times. var volatile bit i2c_scl is pin_c3 var volatile bit i2c_sda is pin_c4 var volatile bit i2c_scl_direction is pin_c3_direction var volatile bit i2c_sda_direction is pin_c4_direction -- include jdelay include vardelay -- ------------------------------------------------------------------------ -- ------------------------------------------------------------------------ -- internal -- ------------------------------------------------------------------------ -- ------------------------------------------------------------------------ -- ------------------------------------------------------------------------ -- _i2c_wait - wait for a change to settle (for internal use only) -- ------------------------------------------------------------------------ -- The delay is determined by i2c_bus_speed and is 1/4 of the cycle time. -- Given the delay resolution of 1 us and all actions required by -- i2c_software routines, the actual bus speed will be lower then the -- configured maximum. -- ------------------------------------------------------------------------ procedure _i2c_wait is -- i2c_100kHz delay_10us(1) end procedure -- ------------------------------------------------------------------------ -- i2c_start - output a start condition -- ------------------------------------------------------------------------ -- ------------------------------------------------------------------------ procedure i2c_start is _i2c_wait i2c_sda_direction = high -- data high _i2c_wait i2c_scl_direction = high -- clock high _i2c_wait i2c_sda_direction = low -- data low _i2c_wait i2c_scl_direction = low -- clock low _i2c_wait end procedure -- ------------------------------------------------------------------------ -- i2c_restart - output a (re)start condition -- ------------------------------------------------------------------------ -- A restart is a start without a previous stop. -- This procedure is provided as part of the API to maintain compatibility -- with the i2c hardware master lib. -- ------------------------------------------------------------------------ procedure i2c_restart is i2c_start end procedure -- ------------------------------------------------------------------------ -- i2c_stop - output a stop condition -- ------------------------------------------------------------------------ -- ------------------------------------------------------------------------ procedure i2c_stop is _i2c_wait i2c_sda_direction = low -- data low _i2c_wait i2c_scl_direction = low -- clock low _i2c_wait i2c_scl_direction = high -- clock high _i2c_wait i2c_sda_direction = high -- data high _i2c_wait end procedure -- ------------------------------------------------------------------------ -- _i2c_bit_out- output a single bit (for internal use only) -- ------------------------------------------------------------------------ -- ------------------------------------------------------------------------ procedure _i2c_bit_out(bit in x) is i2c_sda_direction = x -- high data bit _i2c_wait i2c_scl_direction = high -- clock high _i2c_wait -- if (defined(_i2c_scl_timeout) == true) then -- for _i2c_scl_timeout loop -- if i2c_scl == high then -- exit loop -- end if -- _i2c_wait -- end loop -- else while i2c_scl == low loop end loop -- wait for slow slave -- end if _i2c_wait i2c_scl_direction = low -- clock low _i2c_wait end procedure -- ------------------------------------------------------------------------ -- _i2c_bit_in- input a single bit (for internal use only) -- ------------------------------------------------------------------------ -- ------------------------------------------------------------------------ procedure _i2c_bit_in(bit out x) is -- _i2c_wait i2c_sda_direction = high -- data open _i2c_wait i2c_scl_direction = high -- clock high _i2c_wait -- if (defined(_i2c_scl_timeout) == true) then -- for _i2c_scl_timeout loop -- if i2c_scl == high then -- exit loop -- end if -- _i2c_wait -- end loop -- else while i2c_scl == low loop end loop -- wait for slow slave -- end if _i2c_wait x = i2c_sda -- sample data _i2c_wait i2c_scl_direction = low -- clock low _i2c_wait end procedure -- ------------------------------------------------------------------------ -- i2c_transmit_byte - output one byte -- ------------------------------------------------------------------------ -- return true = okay, false = no ack received -- ------------------------------------------------------------------------ function i2c_send_byte( byte in x ) return bit is var bit b at x : 7 var bit r for 8 loop _i2c_bit_out( b ) x = x << 1 end loop -- wait for an ack condition -- procedure _i2c_wait_ack is _i2c_wait i2c_sda_direction = high -- data open _i2c_wait i2c_scl_direction = high -- clock high _i2c_wait -- if (defined(_i2c_scl_timeout) == true) then -- for _i2c_scl_timeout loop -- if i2c_scl == high then -- exit loop -- end if -- _i2c_wait -- end loop -- else while i2c_scl == low loop end loop -- wait for slow slave -- end if -- check for the slave's acknowledge r = ! i2c_sda _i2c_wait i2c_scl_direction = low -- clock low _i2c_wait return r -- true = okay, false = no ack received end function -- ------------------------------------------------------------------------ -- i2c_receive_byte - read one byte -- ------------------------------------------------------------------------ -- The ACK flag indicated if the byte read must be acked. -- -- In general, all bytes read by the master are acked, except the last one. -- Failing to NACK the last byte read will give unpredictable results. -- (Often it will provide repeatable sequences, where one out of 2 to 4 of -- the reads from a specific device is correct. You are warned!) -- ------------------------------------------------------------------------ function i2c_get_byte( bit in ack) return byte is var byte ret var bit b at ret : 0 for 8 loop ret = ret << 1 _i2c_bit_in( b ) end loop if (ack) then _i2c_bit_out( low ) -- ack else _i2c_bit_out( high ) -- nack end if return ret end function -- ------------------------------------------------------------------------ -- i2c_initialize - initialize the software i2c bus -- ------------------------------------------------------------------------ -- The output latch values are always low, -- the lines are switched open-collector fashion by -- manipulating the direction registers. -- ------------------------------------------------------------------------ procedure i2c_init is i2c_scl = low i2c_sda = low i2c_scl_direction = output i2c_sda_direction = output i2c_stop end procedure i2c_init