📄 i2cdrv.c
字号:
/******************************************************************************************************
I2C driver using I/O port
******************************************************************************************************/
#include <vxworks.h>
#include <semLib.h>
#if (CPU == PPC860 )
#include "m852reg.h"
#include "m852mask.h"
#else
#include "m8260reg.h"
#include "m8260mask.h"
#endif
#include "base.h"
#include "I2CDrv.h"
#if( HARDWARE_VERSION ==2 )
#define SDA_PORT_DAT PADAT
#define SCL_PORT_DAT PADAT
#define SDA_PORT_DIR PADIR
#else //8channel
#define SDA_PORT_DAT M8260_PDDAT
#define SCL_PORT_DAT M8260_PDDAT
#define SDA_PORT_DIR M8260_PDDIR
#endif
void I2C_stop ( void ) ;
void I2C_start ( void ) ;
int I2C_send_byte ( U8 dat ) ;
void I2C_read_byte ( U8 *dat , int flag ) ;
void I2C_set_dir ( int flag ) ;
LOCAL SEM_ID I2C_mutex = NULL ; /*I2C总线互斥访问信号量*/
/*************************************************************************************
* Function : I2C_start
*Description : start the I2C transfer
*
*/
void I2C_start ( void )
{
U32 immBase = vxImmrGet();
/*I2C start condition , SDA falling edge with SCL high level*/
*SDA_PORT_DAT( immBase ) |= I2C_SDA_PIN ;
*SCL_PORT_DAT( immBase ) |= I2C_SCL_PIN ;
software_delay( 100 ) ;
*SDA_PORT_DAT( immBase ) &= ~I2C_SDA_PIN ;
software_delay( 100 ) ;
*SCL_PORT_DAT( immBase ) &= ~I2C_SCL_PIN ;
software_delay( 200 ) ;
}
/*************************************************************************************
* Function : I2C_start
*Description : stop the I2C transfer
*
*/
void I2C_stop ( void )
{
U32 immBase = vxImmrGet();
/*Set SDA pin be output type*/
I2C_set_dir( SDA_OUTPUT ) ;
/*I2C stop condition , SDA rising edge with SCL high level*/
*SDA_PORT_DAT( immBase ) &= ~I2C_SDA_PIN ;
*SCL_PORT_DAT( immBase ) |= I2C_SCL_PIN ;
software_delay(200);
*SDA_PORT_DAT( immBase ) |= I2C_SDA_PIN ;
software_delay( 200 ) ;
}
/*************************************************************************************
* Function : I2C_send_byte
*Description : sent one byte using I2C timing
* > 0 success , < 0 fail
*/
int I2C_send_byte ( U8 dat )
{
U32 immBase = vxImmrGet();
int i ;
/*set pin type be output*/
I2C_set_dir( SDA_OUTPUT ) ;
/*clear SDA line*/
*SDA_PORT_DAT(immBase) &= ~I2C_SDA_PIN ;
software_delay( 200 ) ;
/*loop to send out the 8 bit*/
for( i = 0 ; i < 8 ; i++ )
{
/*NOTE: I2C using rising egde send bit and falling edge to read bit*/
*SCL_PORT_DAT( immBase ) &= ~I2C_SCL_PIN ;
software_delay(200);
if( dat & ( 0x80 >> i ) )
*SDA_PORT_DAT( immBase ) |= I2C_SDA_PIN ;
else
*SDA_PORT_DAT( immBase ) &= ~I2C_SDA_PIN ;
software_delay( 200 );
*SCL_PORT_DAT( immBase ) |= I2C_SCL_PIN ;
software_delay(400);
}
*SCL_PORT_DAT( immBase ) &= ~I2C_SCL_PIN ;
/*Now we should read the slave ack*/
I2C_set_dir( SDA_INPUT ) ;
software_delay(200);
*SCL_PORT_DAT( immBase ) |= I2C_SCL_PIN ;
software_delay(200);
i = *SDA_PORT_DAT( immBase ) & I2C_SDA_PIN ;
*SCL_PORT_DAT( immBase ) &= ~I2C_SCL_PIN ;
software_delay(200);
if( ~i != 0 ) /*We get the ack*/
return 1 ;
/*non ack get , return error*/
return -1 ;
}
/*************************************************************************************
* Function : I2C_read_byte
*Description : read the one byte from I2C
*
*/
void I2C_read_byte ( U8 *dat , int flag )
{
U32 immBase = vxImmrGet();
int i , ret ;
U8 tep ;
I2C_set_dir( SDA_INPUT ) ;
tep = 0 ;
for( i = 0 ; i < 8 ; i++ )
{
*SCL_PORT_DAT( immBase ) |= I2C_SCL_PIN ;
software_delay(400);
if(( *SDA_PORT_DAT( immBase ) & I2C_SDA_PIN ) == I2C_SDA_PIN )
tep |= 0x80 >> i ;
*SCL_PORT_DAT( immBase ) &= ~I2C_SCL_PIN ;
software_delay(200);
}
I2C_set_dir( SDA_OUTPUT ) ;
if( flag )
*SDA_PORT_DAT( immBase ) &= ~I2C_SDA_PIN ; /*more byte , not end*/
else
*SDA_PORT_DAT( immBase ) |= I2C_SDA_PIN ; /*last byte , end read*/
/*Now we should send ack*/
software_delay( 200 );
*SCL_PORT_DAT( immBase ) |= I2C_SCL_PIN ;
software_delay(200);
*SCL_PORT_DAT( immBase ) &= ~I2C_SCL_PIN ;
software_delay(200);
*dat = tep ;
}
/*************************************************************************************
* Function : I2C_set_dir
*Description : change the SDA pin direction
* 1 output ; 0 input
*/
void I2C_set_dir( int flag )
{
U32 immBase = vxImmrGet();
if( flag )
*SDA_PORT_DIR(immBase) |= I2C_SDA_PIN ;
else
*SDA_PORT_DIR(immBase) &= ~I2C_SDA_PIN ;
}
/*************************************************************************************
* Function : I2C_init
*Description : init the I2C driver , config the pin as IO
* create mutex semphone
*/
int I2C_init ()
{
U32 immBase = vxImmrGet();
if( I2C_mutex != NULL )
return ERROR ;
I2C_mutex = semBCreate ( SEM_Q_FIFO , SEM_FULL ) ;
if( I2C_mutex == NULL )
return ERROR ;
#if ( HARDWARE_VERSION == 2 )
*PAODR(immBase) &= ~( I2C_SDA_PIN | I2C_SCL_PIN );
*PAPAR(immBase) &= ~( I2C_SDA_PIN | I2C_SCL_PIN ) ;
/*first config all is output pin*/
*PADIR(immBase) |= ( I2C_SDA_PIN | I2C_SCL_PIN ) ;
/*Pull to high */
*PADAT(immBase) |= I2C_SCL_PIN | I2C_SDA_PIN ;
#else
*M8260_PDODR(immBase) &= ~( I2C_SDA_PIN | I2C_SCL_PIN );
*M8260_PDPAR(immBase) &= ~( I2C_SDA_PIN | I2C_SCL_PIN ) ;
/*first config all is output pin*/
*M8260_PDDIR(immBase) |= ( I2C_SDA_PIN | I2C_SCL_PIN ) ;
/*Pull to high */
*M8260_PDDAT(immBase) |= I2C_SCL_PIN | I2C_SDA_PIN ;
#endif
return OK ;
}
/*************************************************************************************
* Function : I2C_send
*Description : send the data according to the length
*/
int I2C_send ( U8 slave_addr , U8 sub_addr , U16 uLen , U8 *data )
{
int i , ret ;
if( I2C_mutex == NULL )
return ERROR ;
semTake( I2C_mutex , WAIT_FOREVER ) ;
I2C_start( );
/*1. send the chip address*/
slave_addr &= I2C_WRITE ;
ret = I2C_send_byte( slave_addr ) ;
if( ret < 0 )
{
semGive( I2C_mutex ) ;
I2C_stop( );
return -1 ; /*No address ACK*/
}
/*2. send the chip sub address*/
ret = I2C_send_byte( sub_addr ) ;
if( ret < 0 )
{
semGive( I2C_mutex ) ;
I2C_stop( );
return -2 ; /*No sub address ack*/
}
/*Loop to send the all the data*/
for( i = 0 ; i < uLen ; i++ )
{
ret = I2C_send_byte( data[i] ) ;
if( ret < 0 )
{
semGive( I2C_mutex ) ;
I2C_stop( ) ;
return -3 ; /*No data ack*/
}
}
/*all send out , stop I2C*/
semGive( I2C_mutex ) ;
I2C_stop( ) ;
return uLen ;
}
/*************************************************************************************
* Function : I2C_read
*Description : read in data
*/
int I2C_read ( U8 slave_addr , U8 sub_addr , U16 uLen , U8 *data )
{
int i , ret ;
if( I2C_mutex == NULL )
return ERROR ;
semTake( I2C_mutex , WAIT_FOREVER ) ;
I2C_start( );
/*1. send the chip address*/
slave_addr &= I2C_WRITE ;
ret = I2C_send_byte( slave_addr ) ;
if( ret < 0 )
{
semGive( I2C_mutex ) ;
I2C_stop( );
return -1 ; /*No address ACK*/
}
/*2. send the chip sub address*/
ret = I2C_send_byte( sub_addr ) ;
if( ret < 0 )
{
semGive( I2C_mutex ) ;
I2C_stop( );
return -2 ; /*No sub address ack*/
}
I2C_stop ( );
software_delay( 200 ) ;
/*3. really to read byte in*/
I2C_start( );
slave_addr |= I2C_READ ;
ret = I2C_send_byte( slave_addr ) ;
if( ret < 0 )
{
semGive( I2C_mutex ) ;
I2C_stop( );
return -4 ;
}
for( i = 0 ; i < uLen ; i++ )
{
if( i < ( uLen - 1 ) )
I2C_read_byte( &data[i] , 1 ) ; /*should ack*/
else
I2C_read_byte( &data[i] , 0 ) ; /*last byte , no ack*/
}
semGive( I2C_mutex ) ;
I2C_stop( );
return uLen ;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -