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

📄 mcfmbus.c

📁 RTEMS (Real-Time Executive for Multiprocessor Systems) is a free open source real-time operating sys
💻 C
📖 第 1 页 / 共 2 页
字号:
/* MCF5206e MBUS module (I2C bus) driver * * Copyright (C) 2000 OKTET Ltd., St.-Petersburg, Russia * Author: Victor V. Vengerov <vvv@oktet.ru> * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at * * http://www.rtems.com/license/LICENSE. * * @(#) $Id: mcfmbus.c,v 1.2.2.1 2003/09/04 18:45:44 joel Exp $ */#include "mcf5206/mcfmbus.h"#include "mcf5206/mcf5206e.h"#include "i2c.h"/* Events of I2C machine */typedef enum i2c_event {    EVENT_NONE,      /* Spurious event */    EVENT_TRANSFER,  /* Start new transfer */    EVENT_NEXTMSG,   /* Start processing of next message in transfer */    EVENT_ACK,       /* Sending finished with ACK */    EVENT_NACK,      /* Sending finished with NACK */    EVENT_TIMEOUT,   /* Timeout occured */    EVENT_DATA_RECV, /* Data received */    EVENT_ARB_LOST,  /* Arbitration lost */    EVENT_SLAVE      /* Addressed as a slave */} i2c_event;static mcfmbus *mbus;/*** Auxillary primitives ***//* Change state of finite state machine */#define next_state(bus,new_state) \    do {                             \        (bus)->state = (new_state);  \    } while (0)/* Initiate start condition on the I2C bus */#define mcfmbus_start(bus) \    do {                                                    \        *MCF5206E_MBCR((bus)->base) |= MCF5206E_MBCR_MSTA;  \    } while (0)/* Initiate stop condition on the I2C bus */#define mcfmbus_stop(bus) \    do {                                                    \        *MCF5206E_MBCR((bus)->base) &= ~MCF5206E_MBCR_MSTA; \    } while (0)/* Initiate repeat start condition on the I2C bus */#define mcfmbus_rstart(bus) \    do {                                                    \        *MCF5206E_MBCR((bus)->base) |= MCF5206E_MBCR_RSTA;  \    } while (0)/* Send byte to the bus */#define mcfmbus_send(bus,byte) \    do {                                      \        *MCF5206E_MBDR((bus)->base) = (byte); \    } while (0)/* Set transmit mode */#define mcfmbus_tx_mode(bus) \    do {                                                     \        *MCF5206E_MBCR((bus)->base) |= MCF5206E_MBCR_MTX;    \    } while (0)/* Set receive mode */#define mcfmbus_rx_mode(bus) \    do {                                                     \        *MCF5206E_MBCR((bus)->base) &= ~MCF5206E_MBCR_MTX;   \        (void)*MCF5206E_MBDR((bus)->base);                   \    } while (0)/* Transmit acknowledge when byte received */#define mcfmbus_send_ack(bus) \    do {                                                     \        *MCF5206E_MBCR((bus)->base) &= ~MCF5206E_MBCR_TXAK;  \    } while (0)/* DO NOT transmit acknowledge when byte received */#define mcfmbus_send_nack(bus) \    do {                                                     \        *MCF5206E_MBCR((bus)->base) |= MCF5206E_MBCR_TXAK;   \    } while (0)#define mcfmbus_error(bus,err_status) \    do {                                                       \        do {                                                   \           (bus)->cmsg->status = (err_status);                 \           (bus)->cmsg++;                                      \        } while (((bus)->cmsg - (bus)->msg < (bus)->nmsg) &&   \                 ((bus)->cmsg->flags & I2C_MSG_ERRSKIP));      \        bus->cmsg--;                                           \    } while (0)/* mcfmbus_get_event -- *     Read MBUS module status register, determine interrupt reason and *     return appropriate event. * * PARAMETERS: *     bus - pointer to MBUS module descriptor structure * * RETURNS: *     event code */static i2c_eventmcfmbus_get_event(mcfmbus *bus){    i2c_event event;    rtems_unsigned8 status, control;    rtems_interrupt_level level;    rtems_interrupt_disable(level);    status = *MCF5206E_MBSR(bus->base);    control = *MCF5206E_MBCR(bus->base);    if (status & MCF5206E_MBSR_MIF) /* Interrupt occured */    {        if (status & MCF5206E_MBSR_MAAS)        {            event = EVENT_SLAVE;            *MCF5206E_MBCR(bus->base) = control; /* To clear Addressed As Slave                                                    condition */        }        else if (status & MCF5206E_MBSR_MAL) /* Arbitration lost */        {            *MCF5206E_MBSR(bus->base) = status & ~MCF5206E_MBSR_MAL;            event = EVENT_ARB_LOST;        }        else if (control & MCF5206E_MBCR_MTX) /* Trasmit mode */        {            if (status & MCF5206E_MBSR_RXAK)                event = EVENT_NACK;            else                event = EVENT_ACK;        }        else /* Received */        {            event = EVENT_DATA_RECV;        }        /* Clear interrupt condition */        *MCF5206E_MBSR(bus->base) &= ~MCF5206E_MBSR_MIF;    }    else    {        event = EVENT_NONE;    }    rtems_interrupt_enable(level);    return event;}static voidmcfmbus_machine_error(mcfmbus *bus, i2c_event event){    return;}/* mcfmbus_machine -- *     finite state machine for I2C bus protocol * * PARAMETERS: *     bus - pointer to ColdFire MBUS descriptor structure *     event - I2C event * * RETURNS: *     none */static voidmcfmbus_machine(mcfmbus *bus, i2c_event event){    rtems_unsigned8 b;    switch (bus->state)    {        case STATE_IDLE:            switch (event)            {                case EVENT_NEXTMSG:  /* Start new message processing */                    bus->cmsg++;                    /* FALLTHRU */                                case EVENT_TRANSFER: /* Initiate new transfer */                    if (bus->cmsg - bus->msg >= bus->nmsg)                    {                        mcfmbus_stop(bus);                        next_state(bus, STATE_IDLE);                        bus->msg = bus->cmsg = NULL;                        bus->nmsg = bus->byte = 0;                        bus->done(bus->done_arg);                        break;                    }                                        /* Initiate START or REPEATED START condition on the bus */                    if (event == EVENT_TRANSFER)                    {                        mcfmbus_start(bus);                    }                    else /* (event == EVENT_NEXTMSG) */                    {                        mcfmbus_rstart(bus);                    }                                        bus->byte = 0;                    mcfmbus_tx_mode(bus);                                        /* Initiate slave address sending */                    if (bus->cmsg->flags & I2C_MSG_ADDR_10)                    {                        i2c_address a = bus->cmsg->addr;                        b = 0xf0 | (((a >> 8) & 0x03) << 1);                        if (bus->cmsg->flags & I2C_MSG_WR)                        {                            mcfmbus_send(bus, b);                            next_state(bus, STATE_ADDR_1_W);                        }                        else                        {                            mcfmbus_send(bus, b | 1);                            next_state(bus, STATE_ADDR_1_R);                        }                    }                    else                    {                        b = (bus->cmsg->addr & ~0x01);                        if (bus->cmsg->flags & I2C_MSG_WR)                        {                            next_state(bus, STATE_SENDING);                        }                        else                        {                            next_state(bus, STATE_ADDR_7);                            b |= 1;                        }                        mcfmbus_send(bus, b);                    }                    break;                                default:                    mcfmbus_machine_error(bus, event);                    break;            }            break;                case STATE_ADDR_7:            switch (event)            {                case EVENT_ACK:                    mcfmbus_rx_mode(bus);                    if (bus->cmsg->len <= 1)                        mcfmbus_send_nack(bus);                    else                        mcfmbus_send_ack(bus);                    next_state(bus, STATE_RECEIVING);                    break;                                case EVENT_NACK:                    mcfmbus_error(bus, I2C_NO_DEVICE);                    next_state(bus, STATE_IDLE);                    mcfmbus_machine(bus, EVENT_NEXTMSG);                    break;                case EVENT_ARB_LOST:                    mcfmbus_error(bus, I2C_ARBITRATION_LOST);                    next_state(bus, STATE_IDLE);                    mcfmbus_machine(bus, EVENT_NEXTMSG);                    break;                                    default:                    mcfmbus_machine_error(bus, event);                    break;            }            break;        case STATE_ADDR_1_R:                 case STATE_ADDR_1_W:            switch (event)            {                case EVENT_ACK:                {                    rtems_unsigned8 b = (bus->cmsg->addr & 0xff);                    mcfmbus_send(bus, b);                    if (bus->state == STATE_ADDR_1_W)                    {                        next_state(bus, STATE_SENDING);                    }                    else                    {                        i2c_address a;                        mcfmbus_rstart(bus);                        mcfmbus_tx_mode(bus);                        a = bus->cmsg->addr;                        b = 0xf0 | (((a >> 8) & 0x03) << 1) | 1;                        mcfmbus_send(bus, b);                        next_state(bus, STATE_ADDR_7);                    }                    break;                }                                case EVENT_NACK:                    mcfmbus_error(bus, I2C_NO_DEVICE);                    next_state(bus, STATE_IDLE);                    mcfmbus_machine(bus, EVENT_NEXTMSG);

⌨️ 快捷键说明

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