📄 upsd_i2c.lst
字号:
C51 COMPILER V7.20 UPSD_I2C 07/21/2004 16:31:42 PAGE 1
C51 COMPILER V7.20, COMPILATION OF MODULE UPSD_I2C
OBJECT MODULE PLACED IN uPSD_I2C.OBJ
COMPILER INVOKED BY: C:\Keil\C51\BIN\C51.EXE uPSD_I2C.c BROWSE DEBUG OBJECTEXTEND
line level source
1 /*------------------------------------------------------------------------
2 uPSD_I2C.c
3
4 Version:
5 July 2004 Version 1.0 - Initial release.
6
7 Dependencies:
8 FREQ_OSC (from upsd_hardware.h) - used in the calculation that
9 determines the prescaler setting for the I2C bus frequncy.
10
11 Description:
12 The uPSD I2C device driver is intended to provide a standard interrupt I/O
13 set of functions for the I2C unit inside the uPSD3200 MCU. See the
14 functions below for their respective descriptions.
15
16 Important Notes:
17 ----------------
18 - See comments in the upsd_i2c_init() function regarding S2SETUP.
19
20 Known Issues - Slave Mode only:
21 1. This code has only been tested with a START-ADDR-DATA-STOP sequence.
22 It is not known if it works with a START-ADDR-DATA-ReSTART sequence.
23
24 2. The ADDR bit in S2CON is not set (assuming there is an address match)
25 by H/W when a START-ADDRESS is received on the I2C bus and the uPSD32xx
26 was in idle mode. When there is an address match and AA=1, the uPSD32xx
27 does generate an ACK on the 9th SCL clock. The processor is also brought
28 out of idle mode and code execution vectors to the I2C interrupt
29 service routine (ISR).
30
31 Since the ADDR bit is not set indicating that a START-ADDR was received,
32 the I2C interrupt will not be processed appropriately. The ADDR bit is
33 set appropriately if the uPSD was not in idle mode when a START-ADDR is
34 received on the I2C bus.
35
36 Solution:
37 To get around this issue, a S/W flag (i2c_processing) is reset (0) in the
38 I2C init function. It is also reset in the ISR when a STOP or NACK is
39 received from the master. It is set in the ISR when the ADDR bit is
40 detected as set or if i2c_processing was reset.
41
42 The interrupt service routine (ISR), upon seeing the ADRR bit set or the
43 i2c_processing flag reset, processes the interrupt as a START-ADDRESS
44 was received. This solution works well as demonstrated by this example
45 code.
46
47 Limitation of Solution:
48 This solution has only been tested with a START-ADDR-DATA-STOP sequence.
49 It is not known if it will work with a START-ADDR-DATA-ReSTART sequence.
50
51 Note:
52 This demo includes an option to enable or disable compilation of the code
53 that places the uPSD32xx in idle mode between I2C transfers and between each
54 I2C interrupt while in slave mode. It also turns the DK3200 LEDs, LED ONE
55 and LED TWO, on when in idle mode. See the #define and #if used with
C51 COMPILER V7.20 UPSD_I2C 07/21/2004 16:31:42 PAGE 2
56 IDLE_MODE_DEMO. The code that is conditionally compiled with
57 IDLE_MODE_DEMO for toggling the LEDs is only for demonstration purposes and
58 would not normally be included when idle mode is used.
59
60
61 Copyright (c) 2004 ST Microelectronics
62
63 This example demo code is provided as is and has no warranty,
64 implied or otherwise. You are free to use/modify any of the provided
65 code at your own risk in your applications with the expressed limitation
66 of liability (see below) so long as your product using the code contains
67 at least one uPSD product (device).
68
69 LIMITATION OF LIABILITY: NEITHER STMicroelectronics NOR ITS VENDORS OR
70 AGENTS SHALL BE LIABLE FOR ANY LOSS OF PROFITS, LOSS OF USE, LOSS OF DATA,
71 INTERRUPTION OF BUSINESS, NOR FOR INDIRECT, SPECIAL, INCIDENTAL OR
72 CONSEQUENTIAL DAMAGES OF ANY KIND WHETHER UNDER THIS AGREEMENT OR
73 OTHERWISE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
74 -------------------------------------------------------------------------*/
75
76 #pragma CODE
77 #include "upsd3200.h"
78 #include "upsd_hardware.h"
79 #include "upsd_i2c.h"
80
81 #define IDLE_MODE_DEMO 0 //0 = don't compile for slave idle mode demo code
82 //1 = compile slave idle mode demo code
83 //Note: This define is also in upsd_i2c.c file.
84 // This setting must be 0 for Master Mode to
85 // to work.
86 /*-------------------------------------------------------------------------
87 Declaration of local variable
88 -------------------------------------------------------------------------*/
89 unsigned char* i2c_xmit_buf; // message transmit buffer address pointer
90 unsigned char* i2c_rcv_buf; // message receive buffer address pointer
91 unsigned char dummybyte; // dummy byte
92 static unsigned char i2c_data_len,i2c_data_index; // the length and pointer of data buffer
93 bit i2c_master, i2c_xmitr; // callable status flag bits
94 // indicate the status of I2C device, Master or Slave, Transmit or receive
95 static unsigned char i2c_state, slave_addressed; // the current state of I2C operation
96 static unsigned int toggle;
97
98 bit i2c_processing; // used to indicate if an I2C transaction is
99 // currently being processed. (0=no, 1=yes)
100 #if IDLE_MODE_DEMO
extern PSD_REGS PSD8xx_reg; // needed for toggling of LED ONE and LED TWO
#endif
103
104 /*-------------------------------------------------------------------------
105 upsd_i2c_Timeout(Channel)
106
107 This function is used to indicate if the current I2C operation is overtime.
108
109 operation - unsigned char
110 - current I2C operation (I2C_MX/I2C_MR/I2C_SX/I2C_SR).
111 Max_time - unsigned int
112 - the wait time.
113 return value:
114 0: No overtime
115 1: Overtime
116 -------------------------------------------------------------------------*/
117 unsigned char upsd_i2c_Timeout(unsigned char operation,unsigned int Max_time)
C51 COMPILER V7.20 UPSD_I2C 07/21/2004 16:31:42 PAGE 3
118 {
119 1 toggle=0;
120 1 while(i2c_state==operation)
121 1 {
122 2
123 2 #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
137 2
138 2 toggle++;
139 2 if(toggle>=Max_time)return (1);
140 2 }
141 1 return (0);
142 1 }
143
144 /*-------------------------------------------------------------------------
145 upsd_i2c_Busycheck(unsigned int Max_time)
146
147 This function is used to detect I2C bus and wait the I2C bus free.
148
149 return value:
150 0: I2C bus is free
151 1: I2C bus is busy and overtime
152 -------------------------------------------------------------------------*/
153 unsigned char upsd_i2c_Busycheck(unsigned int Max_time)
154 {
155 1 unsigned int count;
156 1 count=0;
157 1 while ((S2STA & BBUSY) != 0)
158 1 {
159 2 count++;
160 2 if(count>=Max_time)return (1);
161 2 }
162 1 return (0);
163 1 }
164
165 /*-------------------------------------------------------------------------
166 unsigned char upsd_i2c_init (unsigned int Bus_Freq,
167 unsigned char Slave_Addr)
168
169 Important Note: See comments below regarding the setting for S2SETUP.
170
171 This function is used to initialize the I2C device with indicated
172 own device address and Bus Freqency. Must be called before other I2C driver
173 function.
174
175 Slave_Addr - unsigned char
176 - Slave address of I2C device.
177 Bus_Freq - unsigned int
178 - I2C bus frequency.
179
C51 COMPILER V7.20 UPSD_I2C 07/21/2004 16:31:42 PAGE 4
180 return value:
181 0: initiate successfully
182 1: Error entry parameter
183 -------------------------------------------------------------------------*/
184 unsigned char upsd_i2c_init (unsigned int Bus_Freq,
185 unsigned char Slave_Addr)
186 {
187 1 // The following table is mid points of the I2C divisor so that rounding will occur
188 1 unsigned int code table[10] = {20,27,45,90,180,360,720,1440,0xffff};
189 1 unsigned char prescaler;
190 1 unsigned int MCU_Freq_mem, divider;
191 1
192 1 if ((Bus_Freq > 833) || (Bus_Freq < 6)) return (1); // Bad Requested range
193 1
194 1 MCU_Freq_mem = (unsigned int) FREQ_OSC; // Caclualte divider needed
195 1 MCU_Freq_mem = MCU_Freq_mem >> 1; // Divide Freq_osc by 2
196 1 divider = MCU_Freq_mem / Bus_Freq;
197 1
198 1 prescaler = 0;
199 1 while (divider > table[prescaler]) prescaler++; // Use table to calc best fit prescaler
200 1 if (prescaler > 7) return(1); // Past max range - bad bus freq
201 1
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -