⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 upsd_i2c.c

📁 Demo for I2C Master and Slave
💻 C
📖 第 1 页 / 共 2 页
字号:
/*------------------------------------------------------------------------uPSD_I2C.cVersion:July 2004 Version 1.0 - Initial release.Dependencies:FREQ_OSC (from upsd_hardware.h) - used in the calculation thatdetermines the prescaler setting for the I2C bus frequncy.Description:The uPSD I2C device driver is intended to provide a standard interrupt I/Oset of functions for the I2C unit inside the uPSD3200 MCU.  See thefunctions below for their respective descriptions.Important Notes:----------------- See comments in the upsd_i2c_init() function regarding S2SETUP.Known Issues - Slave Mode only:1. This code has only been tested with a START-ADDR-DATA-STOP sequence.It is not known if it works with a START-ADDR-DATA-ReSTART sequence.2. The ADDR bit in S2CON is not set (assuming there is an address match) by H/W when a START-ADDRESS is received on the I2C bus and the uPSD32xxwas in idle mode.  When there is an address match and AA=1, the uPSD32xxdoes generate an ACK on the 9th SCL clock.  The processor is also broughtout of idle mode and code execution vectors to the I2C interruptservice routine (ISR).Since the ADDR bit is not set indicating that a START-ADDR was received,the I2C interrupt will not be processed appropriately.  The ADDR bit isset appropriately if the uPSD was not in idle mode when a START-ADDR isreceived on the I2C bus.Solution:To get around this issue, a S/W flag (i2c_processing) is reset (0) in theI2C init function.  It is also reset in the ISR when a STOP or NACK is received from the master.  It is set in the ISR when the ADDR bit is detected as set or if i2c_processing was reset.The interrupt service routine (ISR), upon seeing the ADRR bit set or the i2c_processing flag reset, processes the interrupt as a START-ADDRESS was received.  This solution works well as demonstrated by this example code.  Limitation of Solution:This solution has only been tested with a START-ADDR-DATA-STOP sequence.It is not known if it will work with a START-ADDR-DATA-ReSTART sequence.Note:This demo includes an option to enable or disable compilation of the codethat places the uPSD32xx in idle mode between I2C transfers and between each I2C interrupt while in slave mode.  It also turns the DK3200 LEDs, LED ONE and LED TWO, on when in idle mode.  See the #define and #if used with IDLE_MODE_DEMO.  The code that is conditionally compiled with IDLE_MODE_DEMO for toggling the LEDs is only for demonstration purposes andwould not normally be included when idle mode is used.Copyright (c) 2004 ST MicroelectronicsThis example demo code is provided as is and has no warranty,implied or otherwise.  You are free to use/modify any of the providedcode at your own risk in your applications with the expressed limitationof liability (see below) so long as your product using the code containsat least one uPSD product (device).LIMITATION OF LIABILITY:   NEITHER STMicroelectronics NOR ITS VENDORS OR AGENTS SHALL BE LIABLE FOR ANY LOSS OF PROFITS, LOSS OF USE, LOSS OF DATA,INTERRUPTION OF BUSINESS, NOR FOR INDIRECT, SPECIAL, INCIDENTAL ORCONSEQUENTIAL DAMAGES OF ANY KIND WHETHER UNDER THIS AGREEMENT OROTHERWISE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.-------------------------------------------------------------------------*/#pragma CODE											#include "upsd3200.h"#include "upsd_hardware.h"#include "upsd_i2c.h"#define IDLE_MODE_DEMO 0	//0 = don't compile for slave idle mode demo code							//1 = compile slave idle mode demo code							//Note: This define is also in upsd_i2c.c file.							//      This setting must be 0 for Master Mode to							//       to work./*-------------------------------------------------------------------------Declaration of local variable-------------------------------------------------------------------------*/unsigned char* i2c_xmit_buf;							// message transmit buffer address pointerunsigned char* i2c_rcv_buf;								// message receive buffer address pointerunsigned char dummybyte;								// dummy byte static unsigned char i2c_data_len,i2c_data_index;		// the length and pointer of data buffer bit i2c_master, i2c_xmitr;			    				// callable status flag bits														// indicate the status of I2C device, Master or Slave, Transmit or receivestatic unsigned char i2c_state, slave_addressed;		// the current state of I2C operationstatic unsigned int toggle;bit	i2c_processing;										// used to indicate if an I2C transaction is														//  currently being processed. (0=no, 1=yes)#if IDLE_MODE_DEMOextern PSD_REGS PSD8xx_reg;								// needed for toggling of LED ONE and LED TWO#endif/*-------------------------------------------------------------------------upsd_i2c_Timeout(Channel)This function is used to indicate if the current I2C operation is overtime.operation 	- unsigned char 				- current I2C operation (I2C_MX/I2C_MR/I2C_SX/I2C_SR).Max_time	- unsigned int				- the wait time.return value:0:	No overtime1:	Overtime -------------------------------------------------------------------------*/unsigned char upsd_i2c_Timeout(unsigned char operation,unsigned int Max_time){	toggle=0;	while(i2c_state==operation)	{#if IDLE_MODE_DEMO				    	// Only here for idle mode demonstration in slave mode.	EA = 0;								// Disable interrupts.	if ((i2c_state == I2C_SR) || (i2c_state == I2C_SX))	{		ET0 = 0;						// disable timer 0 int. so only I2C int brings uPSD out of idle mode		PSD8xx_reg.DATAOUT_B&=0xFC;		// PB0 & PB1 = 0 - (LEDs on)		EA = 1;		PCON |= 0x01;   				// puts uPSD in idle mode		PSD8xx_reg.DATAOUT_B|=0x03;		// PB0 & PB1 = 1 - (LEDs off)		ET0 = 1;						// enable timer 0 interrupt	}#endif		toggle++;	  	if(toggle>=Max_time)return (1);	}	return (0);}/*-------------------------------------------------------------------------upsd_i2c_Busycheck(unsigned int Max_time)This function is used to detect I2C bus and wait the I2C bus free.return value:0:	I2C bus is free1:	I2C bus is busy and overtime -------------------------------------------------------------------------*/unsigned char upsd_i2c_Busycheck(unsigned int Max_time){	unsigned int count;	count=0;	while ((S2STA & BBUSY) != 0)	{	  	count++;	  	if(count>=Max_time)return (1);	}	return (0);}/*-------------------------------------------------------------------------unsigned char upsd_i2c_init (unsigned int Bus_Freq,							 unsigned char Slave_Addr) Important Note:  See comments below regarding the setting for S2SETUP.This function is used to initialize the I2C device with indicated own device address and Bus Freqency. Must be called before other I2C driver function.Slave_Addr 	- unsigned char 				- Slave address of I2C device.Bus_Freq	- unsigned int				- I2C bus frequency.return value:0:	initiate successfully 1:	Error entry parameter-------------------------------------------------------------------------*/unsigned char upsd_i2c_init (unsigned int Bus_Freq,					         unsigned char Slave_Addr){    // The following table is mid points of the I2C divisor so that rounding will occur    unsigned int code table[10] = {20,27,45,90,180,360,720,1440,0xffff};    unsigned char prescaler;	unsigned int MCU_Freq_mem, divider;	if ((Bus_Freq > 833) || (Bus_Freq < 6))  return (1);    // Bad Requested range    MCU_Freq_mem = (unsigned int) FREQ_OSC;			      	// Caclualte divider needed	MCU_Freq_mem = MCU_Freq_mem >> 1;						// Divide Freq_osc by 2	divider =  MCU_Freq_mem / Bus_Freq;			         prescaler = 0;    while (divider > table[prescaler]) prescaler++;  	// Use table to calc best fit prescaler    if (prescaler > 7) return(1);						// Past max range - bad bus freq	if (prescaler >= 4) prescaler = (prescaler-4)+0x80;	// fix bit positions for S2CON	S2CON|=prescaler; 	P3SFS |= 0xC0;										// Enable P3.7 for SCL, P3.6 for SDA	// S2SETUP - sets the START/STOP hold detection time in slave mode for noise filtering.    	S2SETUP = 0x81;			// 0x81 is a minimum value that should work for I2C bus clocks 							//  up to 833 KHz and system clocks from 40 MHz down to ~ 8 MHz.							// See the data sheet for details.							// This value should be set appropriately based on the system clock							//  as well as the maximum I2C bus clock to be supported by the							//  system.  The amount of noise in the system should be considered							//  when determining this setting.  The more noise, the longer the							//  hold time should be.  							// Important Note: If the hold time is too long, then valid START/STOP							//  bits will be rejected.  The shorter the hold time, the less							//  immune the I2C port is to noise.  S2SETUP should be adjusted							//  appropriately to the system environment.	IPA |= 0x02;						// set high priority for EI2C	IEA |= 0x02;						// set EI2C I2C Int. Enable bit	S2ADR = Slave_Addr;					// set up i2c address   	i2c_processing = 0;		            // indicate not processing I2C transaction	S2CON |= ENI;		   				// Set ENI (Enable I2C-2)		S2CON &= ~AA;					    // disable Acknowledge	return(0);}/*-------------------------------------------------------------------------unsigned char upsd_i2c_Master_Xmit (unsigned char Slave_Addr, 							unsigned char* Data_Ptr,							unsigned char N)This function is used to transmit special length of data to Slave, only for I2C master.Slave_Addr 	- unsigned char 				- Slave address of I2C device.Data_Ptr	- unsigned char*			- address pointer of transimt bufferN			- unsigned char			- the length of data buffer to be transmited. 			return value:I2C_MX_END		4			//Indicate a transmitting has been finished in master modelI2C_TIME_OUT	9			//Indicate I2C overtime.I2C_NACK		13			//Indicate I2C no acknowledgeI2C_BUSLOST		14			//Indicate I2C bus lostI2C_BUSY		16			//Indicate I2C bus is busy-------------------------------------------------------------------------*/unsigned char upsd_i2c_Master_Xmit (unsigned char Slave_Addr, 							unsigned char* Data_Ptr,							unsigned char N){	EA=0;	i2c_master = 1;  					// set up for master	i2c_xmit_buf=Data_Ptr;	if(upsd_i2c_Busycheck(1000)==1){		S2CON&=~STA;		S2CON|=STO;		S2DAT=dummy;		i2c_state=I2C_BUSY;		return (i2c_state); 	}					 				// Bus busy and return current state of I2C	i2c_data_len=N;	     				// Initialize i2c_data_len to specify communicated data length	i2c_master = 1;	i2c_xmitr = 1;						// set up for master transmitter	S2DAT = Slave_Addr;					// set up i2c address	S2CON |= ENI;		   				// Set ENI (Enable I2C-2)	S2CON &= ~STO;						// Clr STO in S1CON	S2CON |= STA;						// Set STA (Send start bit)	S2CON &= ~AA;						// Clr AA in S2CON, because acknowledge should be provided by receiver		i2c_data_index=0;	i2c_state=I2C_MX;					// set up i2c current state I2C_MX.	EA=1;	if(upsd_i2c_Timeout(I2C_MX,1000)==1){		EA=0;		S2CON&=~STA;		S2CON|=STO;		S2DAT=dummy;		S2CON&=~ENI;S2CON|=ENI;		i2c_state=I2C_TIME_OUT;		return (i2c_state);	}					   				// I2C master transmit timeout	else {		EA=0;		return(i2c_state);	} 									// return I2C current state}									     /*-------------------------------------------------------------------------unsigned char upsd_i2c_Master_Recv (unsigned char Slave_Addr, 							unsigned char* Data_Ptr,							unsigned char N)This function is used to receive special length of data from Slave, only forI2C Master.Slave_Addr 	- unsigned char 				- Slave address of I2C device.Data_Ptr	- unsigned char*			- address pointer of transimt bufferN			- unsigned char			- the length of data buffer to be transmited. 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -