OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [devs/] [i2c/] [cortexm/] [lm3s/] [current/] [src/] [i2c_lm3s.c] - Blame information for rev 786

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      i2c_lm3s.c
4
//
5
//      I2C driver for Stellaris Cortex M3 microcontroller
6
//
7
//==========================================================================
8
// ####ECOSGPLCOPYRIGHTBEGIN####                                            
9
// -------------------------------------------                              
10
// This file is part of eCos, the Embedded Configurable Operating System.   
11
// Copyright (C) 2011 Free Software Foundation, Inc.
12
//
13
// eCos is free software; you can redistribute it and/or modify it under    
14
// the terms of the GNU General Public License as published by the Free     
15
// Software Foundation; either version 2 or (at your option) any later      
16
// version.                                                                 
17
//
18
// eCos is distributed in the hope that it will be useful, but WITHOUT      
19
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
20
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
21
// for more details.                                                        
22
//
23
// You should have received a copy of the GNU General Public License        
24
// along with eCos; if not, write to the Free Software Foundation, Inc.,    
25
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
26
//
27
// As a special exception, if other files instantiate templates or use      
28
// macros or inline functions from this file, or you compile this file      
29
// and link it with other works to produce a work based on this file,       
30
// this file does not by itself cause the resulting work to be covered by   
31
// the GNU General Public License. However the source code for this file    
32
// must still be made available in accordance with section (3) of the GNU   
33
// General Public License v2.                                               
34
//
35
// This exception does not invalidate any other reasons why a work based    
36
// on this file might be covered by the GNU General Public License.         
37
// -------------------------------------------                              
38
// ####ECOSGPLCOPYRIGHTEND####                                              
39
//==========================================================================
40
//#####DESCRIPTIONBEGIN####
41
//
42
// Author(s):     ccoutand
43
// Contributors:  
44
// Date:          2011-01-18
45
// Original:      Uwe Kindler, Bart Veer
46
//                I2C driver for motorola coldfire processor
47
// Description:   I2C driver for Stellaris Cortex M3 microcontroller
48
//                The RX part of the driver has not been tested.
49
//
50
//####DESCRIPTIONEND####
51
//==========================================================================
52
 
53
#include <pkgconf/system.h>
54
 
55
#include <cyg/infra/cyg_type.h>
56
#include <cyg/infra/cyg_ass.h>
57
#include <cyg/infra/diag.h>
58
#include <cyg/io/i2c.h>
59
#include <cyg/io/i2c_lm3s.h>
60
#include <cyg/hal/hal_arch.h>
61
#include <cyg/hal/hal_io.h>
62
#include <cyg/hal/hal_intr.h>
63
#include <cyg/hal/drv_api.h>
64
 
65
#ifdef CYGPKG_DEVS_I2C_CORTEXM_LM3S_TRACE
66
# define I2C_TRACE(args...) diag_printf(args)
67
#else
68
# define I2C_TRACE(args...)
69
#endif
70
 
71
#define I2C_DAT(_extra_)     (_extra_ + CYGHWR_HAL_LM3S_I2C_MDR)
72
#define I2C_ADR(_extra_)     (_extra_ + CYGHWR_HAL_LM3S_I2C_MSA)
73
#define I2C_SR(_extra_)      (_extra_ + CYGHWR_HAL_LM3S_I2C_MCS)
74
#define I2C_CR(_extra_)      (_extra_ + CYGHWR_HAL_LM3S_I2C_MCS)
75
#define I2C_MCR(_extra_)     (_extra_ + CYGHWR_HAL_LM3S_I2C_MCR)
76
#define I2C_MTPR(_extra_)    (_extra_ + CYGHWR_HAL_LM3S_I2C_MTPR)
77
#define I2C_MCR(_extra_)     (_extra_ + CYGHWR_HAL_LM3S_I2C_MCR)
78
#define I2C_IMR(_extra_)     (_extra_ + CYGHWR_HAL_LM3S_I2C_MIMR)
79
#define I2C_ICR(_extra_)     (_extra_ + CYGHWR_HAL_LM3S_I2C_MICR)
80
 
81
#define WAIT_BUS_READY( __sr__, __extra__ )                     \
82
{                                                               \
83
    if (!__extra__->i2c_owner) {                                \
84
        __extra__->i2c_got_nack = 0;                            \
85
        __extra__->i2c_owner = 1;                               \
86
        HAL_READ_UINT32(I2C_SR(__extra__->i2c_base), __sr__);   \
87
        while (__sr__ & CYGHWR_HAL_LM3S_I2C_MCS_BUSBSY) {       \
88
          HAL_READ_UINT32(I2C_SR(__extra__->i2c_base),__sr__);  \
89
        }                                                       \
90
    }                                                           \
91
}
92
 
93
 
94
static cyg_uint32
95
lm3s_i2c_isr(cyg_vector_t vec, cyg_addrword_t data)
96
{
97
    lm3s_i2c_extra *extra = (lm3s_i2c_extra *) data;
98
    cyg_uint32      sr,
99
                    dr;
100
    cyg_uint32      result = CYG_ISR_HANDLED;
101
    cyg_uint32      reg = CYGHWR_HAL_LM3S_I2C_MCS_RUN;
102
    cyg_uint8       tx_data = *extra->i2c_data.i2c_tx_data;
103
 
104
    // Read the current status, then clear the interrupt
105
    HAL_READ_UINT32(I2C_SR(extra->i2c_base), sr);
106
    HAL_WRITE_UINT32(I2C_ICR(extra->i2c_base), 1);
107
 
108
    // What to do next depends on the current transfer mode.
109
    if (LM3S_I2C_XFER_MODE_TX == extra->i2c_mode) {
110
        I2C_TRACE("I2C: TX IRQ handling\n");
111
        if (sr & CYGHWR_HAL_LM3S_I2C_MCS_ERR) {
112
            // Lost the bus, abort the transfer. count has already been
113
            // decremented. Assume the byte did not actually arrive.
114
            extra->i2c_count += 1;
115
            // Arbitration  lost, stop
116
            if (sr & CYGHWR_HAL_LM3S_I2C_MCS_ARBLST) {
117
                reg = CYGHWR_HAL_LM3S_I2C_MCS_STOP;
118
                HAL_WRITE_UINT32(I2C_CR(extra->i2c_base), reg);
119
            }
120
            // This byte has been sent but the device cannot accept
121
            // any more. The nack must be remembered. Otherwise if
122
            // we got a nack for the last byte in a tx then the
123
            // calling code will think the entire tx succeeded,
124
            // and there will be problems if the next call is
125
            // another tx without a repeated start.
126
            if ((sr & CYGHWR_HAL_LM3S_I2C_MCS_ADRACK) |
127
                (sr & CYGHWR_HAL_LM3S_I2C_MCS_DATACK)) {
128
                extra->i2c_got_nack = 1;
129
            }
130
            result = CYG_ISR_HANDLED | CYG_ISR_CALL_DSR;
131
            I2C_TRACE("I2C TX, bus arbitration error\n");
132
        } else if (0 == extra->i2c_count) {
133
            // No more bytes to send.
134
            result = CYG_ISR_HANDLED | CYG_ISR_CALL_DSR;
135
        } else {
136
            // Send byte
137
            HAL_WRITE_UINT32(I2C_DAT(extra->i2c_base), (cyg_uint32)tx_data);
138
            extra->i2c_data.i2c_tx_data += 1;
139
            extra->i2c_count -= 1;
140
            // Last byte
141
            if ((0 == extra->i2c_count) && extra->send_stop) {
142
                reg |= CYGHWR_HAL_LM3S_I2C_MCS_STOP;
143
            }
144
            HAL_WRITE_UINT32(I2C_CR(extra->i2c_base), reg);
145
        }
146
    } else if (LM3S_I2C_XFER_MODE_RX == extra->i2c_mode) {
147
        I2C_TRACE("I2C: RX IRQ handling\n");
148
        if (sr & CYGHWR_HAL_LM3S_I2C_MCS_ERR) {
149
            // Lost the bus? Maybe a spurious stop
150
            result = CYG_ISR_HANDLED | CYG_ISR_CALL_DSR;
151
        } else {
152
            if (2 == extra->i2c_count) {
153
                // Received one, one more to go,
154
                // and that one should be nacked.
155
                if (!extra->i2c_send_nack) {
156
                    reg |= CYGHWR_HAL_LM3S_I2C_MCS_ACK;
157
                }
158
                if (extra->send_stop) {
159
                    reg |= CYGHWR_HAL_LM3S_I2C_MCS_STOP;
160
                }
161
                HAL_WRITE_UINT32(I2C_CR(extra->i2c_base), reg);
162
            } else if (1 == extra->i2c_count) {
163
                // Received the last byte.
164
                result = CYG_ISR_HANDLED | CYG_ISR_CALL_DSR;
165
            }
166
            HAL_READ_UINT32(I2C_DAT(extra->i2c_base), dr);
167
            *(extra->i2c_data.i2c_rx_data) = (cyg_uint8)dr;
168
            extra->i2c_data.i2c_rx_data += 1;
169
            extra->i2c_count -= 1;
170
        }
171
    } else {
172
        // Invalid state? Some kind of spurious interrupt?
173
        // Just ignore it.
174
        I2C_TRACE("I2C spurious interrupt\n");
175
    }
176
 
177
    HAL_INTERRUPT_ACKNOWLEDGE(extra->i2c_isr_id);
178
 
179
    return result;
180
}
181
 
182
 
183
static void
184
lm3s_i2c_dsr(cyg_vector_t vec, cyg_ucount32 count, cyg_addrword_t data)
185
{
186
    lm3s_i2c_extra *extra = (lm3s_i2c_extra *) data;
187
    extra->i2c_completed = 1;
188
    cyg_drv_cond_signal(&(extra->i2c_wait));
189
}
190
 
191
 
192
// A transfer has been started. Wait for completion
193
static inline void
194
lm3s_i2c_doit(lm3s_i2c_extra * extra)
195
{
196
    cyg_drv_mutex_lock(&(extra->i2c_lock));
197
    cyg_drv_dsr_lock();
198
    while (!extra->i2c_completed) {
199
        cyg_drv_cond_wait(&(extra->i2c_wait));
200
    }
201
    cyg_drv_dsr_unlock();
202
    cyg_drv_mutex_unlock(&(extra->i2c_lock));
203
}
204
 
205
 
206
static inline void
207
lm3s_i2c_stopit(lm3s_i2c_extra * extra)
208
{
209
    extra->i2c_lost_arb = 0;
210
    extra->i2c_owner = 0;
211
    extra->i2c_mode = LM3S_I2C_XFER_MODE_INVALID;
212
}
213
 
214
 
215
void
216
lm3s_i2c_stop(const cyg_i2c_device * dev)
217
{
218
    lm3s_i2c_extra *extra = (lm3s_i2c_extra *) dev->i2c_bus->i2c_extra;
219
    lm3s_i2c_stopit(extra);
220
}
221
 
222
 
223
static cyg_bool
224
lm3s_i2c_handle_xfer(lm3s_i2c_extra * extra, int address)
225
{
226
    cyg_uint32      sr;
227
    cyg_uint8       data = *extra->i2c_data.i2c_tx_data;
228
    cyg_uint32      reg = CYGHWR_HAL_LM3S_I2C_MCS_RUN;
229
 
230
    // Nothing to send or receive
231
    if (extra->i2c_count == 0)
232
        return 0;
233
 
234
    // Take the bus ownership
235
    WAIT_BUS_READY(sr, extra);
236
 
237
    // This can be a start or repeated start
238
    if (extra->send_start) {
239
        reg |= CYGHWR_HAL_LM3S_I2C_MCS_START;
240
        HAL_WRITE_UINT32(I2C_ADR(extra->i2c_base), address);
241
    }
242
    // TX transfer
243
    if (extra->i2c_mode == LM3S_I2C_XFER_MODE_TX) {
244
        extra->i2c_data.i2c_tx_data += 1;
245
        extra->i2c_count -= 1;
246
        HAL_WRITE_UINT32(I2C_DAT(extra->i2c_base), (cyg_uint32)data);
247
 
248
        // Single byte transfer
249
        if (extra->send_stop && (extra->i2c_count == 0)) {
250
            reg |= CYGHWR_HAL_LM3S_I2C_MCS_STOP;
251
        }
252
    } else {
253
        // Single byte transfer, set the STOP bit
254
        if (extra->send_stop && (extra->i2c_count == 1)) {
255
            reg |= CYGHWR_HAL_LM3S_I2C_MCS_STOP;
256
        }
257
        // Do not ACK last byte per user request
258
        if (!extra->i2c_send_nack || !(extra->i2c_count == 1)) {
259
            reg |= CYGHWR_HAL_LM3S_I2C_MCS_ACK;
260
        }
261
    }
262
 
263
    HAL_WRITE_UINT32(I2C_CR(extra->i2c_base), reg);
264
 
265
    return 1;
266
}
267
 
268
 
269
cyg_uint32
270
lm3s_i2c_tx(const cyg_i2c_device * dev, cyg_bool send_start,
271
            const cyg_uint8 *tx_data, cyg_uint32 count, cyg_bool send_stop)
272
{
273
    lm3s_i2c_extra *extra = (lm3s_i2c_extra *) dev->i2c_bus->i2c_extra;
274
    extra->send_stop = send_stop;
275
    extra->send_start = send_start;
276
    extra->i2c_count = count;
277
 
278
    if (!extra->i2c_lost_arb) {
279
        extra->i2c_completed = 0;
280
        extra->i2c_mode = LM3S_I2C_XFER_MODE_TX;
281
 
282
        if (send_start || !extra->i2c_got_nack) {
283
            I2C_TRACE
284
                ("I2C: TX to %2x, data %2x, count: %4d, START flag: %s\n",
285
                 dev->i2c_address, *tx_data, count,
286
                 (send_start == true) ? "true" : "false");
287
            extra->i2c_data.i2c_tx_data = tx_data;
288
            if (!lm3s_i2c_handle_xfer(extra, (dev->i2c_address << 1) | 0x00)) {
289
                return 0;
290
            }
291
            lm3s_i2c_doit(extra);
292
        }
293
 
294
    }
295
    if (send_stop) {
296
        I2C_TRACE("I2C: TX send stop\n");
297
        lm3s_i2c_stopit(extra);
298
    }
299
 
300
    I2C_TRACE("I2C: TX count %d\n", extra->i2c_count);
301
 
302
    // tx() should return the number of bytes actually transmitted.
303
    // ISR() increments extra->count after a failure, which leads to
304
    // an edge condition when send_start and there is no acknowledgment
305
    // of the address byte.
306
    if (extra->i2c_count > count) {
307
        return 0;
308
    }
309
 
310
    return count - extra->i2c_count;
311
}
312
 
313
 
314
cyg_uint32
315
lm3s_i2c_rx(const cyg_i2c_device * dev, cyg_bool send_start,
316
            cyg_uint8 *rx_data, cyg_uint32 count, cyg_bool send_nack,
317
            cyg_bool send_stop)
318
{
319
    lm3s_i2c_extra *extra = (lm3s_i2c_extra *) dev->i2c_bus->i2c_extra;
320
    extra->i2c_count = count;
321
    extra->i2c_send_nack = send_nack;
322
    extra->send_stop = send_stop;
323
    extra->send_start = send_start;
324
 
325
    if (!extra->i2c_lost_arb) {
326
        extra->i2c_completed = 0;
327
        extra->i2c_data.i2c_rx_data = rx_data;
328
        extra->i2c_mode = LM3S_I2C_XFER_MODE_RX;
329
        I2C_TRACE("I2C: RX to %2x, count: %4d, START flag: %s\n",
330
                  dev->i2c_address, count,
331
                  (send_start == true) ? "true" : "false");
332
        if (!lm3s_i2c_handle_xfer(extra, (dev->i2c_address << 1) | 0x01)) {
333
            return 0;
334
        }
335
        lm3s_i2c_doit(extra);
336
    }
337
 
338
    if (send_stop) {
339
        I2C_TRACE("I2C: RX send stop\n");
340
        lm3s_i2c_stopit(extra);
341
    }
342
 
343
    return count - extra->i2c_count;
344
}
345
 
346
 
347
// ----------------------------------------------------------------------------
348
// The functions needed for all I2C devices.
349
 
350
void
351
lm3s_i2c_init(struct cyg_i2c_bus *bus)
352
{
353
    lm3s_i2c_extra *extra = (lm3s_i2c_extra *) bus->i2c_extra;
354
    cyg_uint32      tpr =
355
        ((hal_lm3s_i2c_clock() /
356
          (20 * CYGNUM_HAL_CORTEXM_LM3S_I2C_CLK_SPEED)) - 1);
357
 
358
    I2C_TRACE("I2C INIT, TPR register: %d\n", tpr);
359
 
360
    cyg_drv_mutex_init(&extra->i2c_lock);
361
    cyg_drv_cond_init(&extra->i2c_wait, &extra->i2c_lock);
362
    cyg_drv_interrupt_create(extra->i2c_isr_id,
363
                             extra->i2c_isr_pri,
364
                             (cyg_addrword_t)extra,
365
                             &lm3s_i2c_isr,
366
                             &lm3s_i2c_dsr,
367
                             &(extra->i2c_interrupt_handle),
368
                             &(extra->i2c_interrupt_data));
369
    cyg_drv_interrupt_attach(extra->i2c_interrupt_handle);
370
 
371
    // Enable I2C peripheral, it is left to the variant/platform HAL to
372
    // configure the SDA and SCL IOs.
373
    CYGHWR_HAL_LM3S_PERIPH_SET(extra->i2c_periph, 1);
374
 
375
    // Enable Master mode
376
    HAL_WRITE_UINT32(I2C_MCR(extra->i2c_base), CYGHWR_HAL_LM3S_I2C_MCR_MFE);
377
 
378
    // Set I2C bus speed
379
    HAL_WRITE_UINT32(I2C_MTPR(extra->i2c_base), tpr);
380
 
381
    // Enable Interrupt
382
    HAL_WRITE_UINT32(I2C_IMR(extra->i2c_base), 1);
383
 
384
    // Interrupts can now be safely unmasked
385
    HAL_INTERRUPT_UNMASK(extra->i2c_isr_id);
386
}
387
 
388
//---------------------------------------------------------------------------
389
// EOF i2c_lm3s.c

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.