打印

ST912 I2C问题

[复制链接]
3602|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Flandy|  楼主 | 2007-9-27 10:54 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
ST, I2c, TI, IO, TE
我在调试I2C中断方式的接收数据流程时碰到如下问题
如上图波形,在一个接收流程完成后,Stop condition没有成功发送. 流程如下
Start[主]  SlaveAddr[主] Ack SubAddr[主] Ack Stop[主] RepeatStart[主] SlaveAddr[主] Ack Data Nack[主] Stop[主](此Stop未成功发送)
下面是UCOSII下的I2C程序文件,请帮我看下是什么问题造成的,谢谢!!

//File         : I2CDev.C
//Created by   : Kuang Hao
#include "Config.h"
//tI2C_COMM_CB _I2CCommCtrlBlock;
tI2C_CB _I2CCtrlBlock[I2C_BUS_COUNT];
static void __InitI2CGPIO(void) {
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_StructInit(&GPIO_InitStruct);
    //* KEYBOARD
    //* P2.0 I2C0_CLKOUT
    //* P2.1 I2C0_DOUT
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
    GPIO_InitStruct.GPIO_Direction = GPIO_PinOutput;
    GPIO_InitStruct.GPIO_Type = GPIO_Type_PushPull;
    GPIO_InitStruct.GPIO_IPConnected = GPIO_IPConnected_Enable;
    GPIO_InitStruct.GPIO_Alternate = GPIO_OutputAlt2;
    GPIO_Init(GPIO2, &GPIO_InitStruct);
    //* EEPROM
    //* P2.2 I2C1_CLKOUT
    //* P2.3 I2C1_DOUT
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;
    GPIO_InitStruct.GPIO_Direction = GPIO_PinOutput;
    GPIO_InitStruct.GPIO_Type = GPIO_Type_PushPull;
    GPIO_InitStruct.GPIO_IPConnected = GPIO_IPConnected_Enable;
    GPIO_InitStruct.GPIO_Alternate = GPIO_OutputAlt2;
    GPIO_Init(GPIO2, &GPIO_InitStruct);
}

static void __InitI2CCB(void) {
    //* Init I2C communication contrl block
    _I2CCtrlBlock[0].CommCb.bAddr = 0;
    _I2CCtrlBlock[0].CommCb.iSize = 0;
    _I2CCtrlBlock[0].CommCb.pData = (void *)0;
    _I2CCtrlBlock[0].CommCb.bDirection = I2C_MODE_TRANSMITTER;
    
    _I2CCtrlBlock[1].CommCb.bAddr = 0;
    _I2CCtrlBlock[1].CommCb.iSize = 0;
    _I2CCtrlBlock[1].CommCb.pData = (void *)0;
    _I2CCtrlBlock[1].CommCb.bDirection = I2C_MODE_TRANSMITTER;
    //* Init I2C contrl block
    _I2CCtrlBlock[0].I2Cx = I2C0;
    _I2CCtrlBlock[0].pEventSem = OSSemCreate(1);
    _I2CCtrlBlock[0].pEventMB = OSMboxCreate((void *)0);
    _I2CCtrlBlock[1].I2Cx = I2C1;
    _I2CCtrlBlock[1].pEventSem = OSSemCreate(1);
    _I2CCtrlBlock[1].pEventMB = OSMboxCreate((void *)0);

}
// * KEYBOARD   -- I2C0 
// * EEPROM     -- I2C1
void InitI2C(u16 I2C0Addr, u16 I2C1Addr) {
    I2C_InitTypeDef I2C_Struct;
    //* InitI2CContrlBlock
    __InitI2CCB();
    //* GPIO0 Config 
    __InitI2CGPIO();
    //* I2C0 Configuration 
    I2C_Struct.I2C_GeneralCall = I2C_GeneralCall_Disable;
    I2C_Struct.I2C_Ack = I2C_Ack_Enable;
    I2C_Struct.I2C_CLKSpeed = 100000;
    I2C_Struct.I2C_OwnAddress = I2C0Addr;
    I2C_Init(I2C0, &I2C_Struct);
    //* I2C1 Configuration 
    //* we keep the same config as I2C0 for the other I2C_Struct members 
    //* We change just the address 
    I2C_Struct.I2C_OwnAddress = I2C1Addr;
    I2C_Init(I2C1, &I2C_Struct);
    I2C_Cmd(I2C0, ENABLE);
    I2C_Cmd(I2C1, ENABLE);
    I2C_ITConfig(I2C1, ENABLE);
    I2C_ITConfig(I2C0, ENABLE);
}
// ******************************************************************************************************
// * 参数 :             [IN]tI2C_CB *I2C_CBx, 
// *                    [IN]INT8U bSlaveAddr,   // * 从设备地址
// *                    [IN]INT16U iSubAddr,    // * 从设备子地址
// *                    [IN]INT8U *bData,       // * 待传输的数据
// *                    [IN]INT32U iDataSize    // * 传输的数据长度
// *                    [IN]INT8U bDirection    // * 传输的数据的方向 
// *                                            // * I2C_MODE_TRANSMITTER 
// *                                            // * I2C_MODE_RECEIVER
// * 返回 :             [OUT]INT32U             // * 写入的数据长度.
// * 创建 :             Kuanghao
// ******************************************************************************************************
static INT8U __WriteI2CByte(tI2C_CB *I2C_CBx, 
                            INT8U bSlaveAddr, 
                            INT8U *bData, 
                            INT32U iDataSize, 
                            INT8U bDirection
                           ) 
{
    INT8U bErr = OS_NO_ERR;
    INT8U Msg = 0;
#if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */
    OS_CPU_SR     cpu_sr;
    cpu_sr = cpu_sr;
#endif
    OS_ENTER_CRITICAL();
    I2C_CBx->CommCb.bAddr = bSlaveAddr & 0xFE;   //* 存储发送地址 
    I2C_CBx->CommCb.iSize = iDataSize;           //* 存储写字节数 
    I2C_CBx->CommCb.pData = bData;               //* 存储写的数据的指针 
    I2C_CBx->CommCb.bDirection = bDirection;
    OS_EXIT_CRITICAL();
    I2C_GenerateStart(I2C_CBx->I2Cx, ENABLE);
    Msg = (INT8U)OSMboxPend(I2C_CBx->pEventMB, I2C_COMM_TIMEOUT_TICKS, &bErr);
    if(bDirection == I2C_MODE_TRANSMITTER) {
        if((Msg == MBOX_I2C_WRITE_DATA) & (bErr == OS_NO_ERR))
            return (iDataSize - I2C_CBx->CommCb.iSize);
    } else {
        if((Msg == MBOX_I2C_READ_DATA) & (bErr == OS_NO_ERR))
            return (iDataSize - I2C_CBx->CommCb.iSize);
    }
    return FALSE;
}
// ******************************************************************************************************
// * 参数 :             [IN]tI2C_CB *I2C_CBx, 
// *                    [IN]const INT8U *pData, // * 写入的数据(包含子地址数据)
// *                    [IN]INT8U bSlaveAddr,   // * 从设备地址
// *                    [IN]INT32U iDataSize    // * 传输的数据长度,不包括子地址长度.
// * 返回 :             [OUT]INT32U 写入的数据长度.
// * 创建 :             Kuanghao
// * 注意 :             数据区内包含子地址.
// ******************************************************************************************************
INT32U WriteI2CData(tI2C_CB *I2C_CBx, 
                    INT8U bSlaveAddr,   // * 从设备地址
                    INT8U *pData,       // * 写入的数据
                    INT32U iDataSize    // * 传输的数据长度,不包括子地址长度.
                   ) 
{
    INT8U bErr = OS_NO_ERR;
    OSSemPend(I2C_CBx->pEventSem, I2C_COMM_TIMEOUT_TICKS, &bErr);
    // * 写数据
    if(!__WriteI2CByte(I2C_CBx, bSlaveAddr, pData, iDataSize, I2C_MODE_TRANSMITTER))        // * 写失败
        return (iDataSize - I2C_CBx->CommCb.iSize);// return write data size;
    OSSemPost(I2C_CBx->pEventSem);
    return (iDataSize - I2C_CBx->CommCb.iSize);
}

// ******************************************************************************************************
// * 参数 :             [IN]tI2C_CB *I2C_CBx, 
// *                    [OUT]INT8U *pData,      // * 读取的数据
// *                    [IN]INT8U bSlaveAddr,   // * 从设备地址
// *                    [IN]INT16U iSubAddr,    // * 从设备子地址
// *                    [IN]INT8U bSubAddrLen,  // * 子地址长度 0 ~ 2
// *                    [IN]INT32U iDataSize    // * 传输的数据长度,不包括子地址长度.
// * 返回 :             [OUT]INT32U 读出的数据长度.
// * 创建 :             Kuanghao
// ******************************************************************************************************
INT32U ReadI2CData(tI2C_CB *I2C_CBx, 
                   INT8U bSlaveAddr,   // * 从设备地址
                   INT16U iSubAddr,    // * 从设备子地址
                   INT8U bSubAddrLen,  // * 子地址长度 0 ~ 2
                   INT8U *pData,       // * 读取的数据
                   INT32U iDataSize    // * 传输的数据长度,不包括子地址长度.
                  )
{
    INT8U bErr = OS_NO_ERR;
    INT8U bSubAddr[2];
    INT8U bWriteSub = TRUE;
    OSSemPend(I2C_CBx->pEventSem, I2C_COMM_TIMEOUT_TICKS, &bErr);
    switch(bSubAddrLen) {
        case 0: // * 无子地址
            bWriteSub = FALSE;
            break;
        case 1:
            bSubAddr[0] = (INT8U)iSubAddr;
            break;
        case 2:
            bSubAddr[0] = (INT8U)(iSubAddr >> 8);
            bSubAddr[1] = (INT8U)iSubAddr;
            break;
        default:
            break;
    }
    if(bWriteSub) {
        // * 写子地址
        if(!__WriteI2CByte(I2C_CBx, bSlaveAddr, bSubAddr, bSubAddrLen, 
                           I2C_MODE_TRANSMITTER))     // * 写失败
            return -1;
    }
    // * 对于无子地址器件此处为正常Start 对于有子地址器件此处为ReStart.
    // * 读数据
    if(!__WriteI2CByte(I2C_CBx, bSlaveAddr, pData, iDataSize, 
                       I2C_MODE_RECEIVER))            // * 读失败
        return (iDataSize - I2C_CBx->CommCb.iSize);   // return read data size;
    OSSemPost(I2C_CBx->pEventSem);
    return (iDataSize - I2C_CBx->CommCb.iSize);
}

void I2CIRQService(tI2C_CB *I2C_CBx) {
    switch (I2C_GetLastEvent(I2C_CBx->I2Cx))
    {
        // * 在主模式下产生Start condition EV5
        case I2C_EVENT_MASTER_MODE_SELECT: 
        // * 传输I2C设备地址
            I2C_Send7bitAddress(I2C_CBx->I2Cx, I2C_CBx->CommCb.bAddr, I2C_CBx->CommCb.bDirection);
            break;
        // * 在主模式下设备地址字节发送成功 EV6
        case I2C_EVENT_MASTER_MODE_SELECTED:           
            //* Clear EV6 by set again the PE bit
            I2C_CBx->I2Cx->CR |=  0x20;
            if (I2C_CBx->CommCb.bDirection == I2C_MODE_TRANSMITTER) { //* 写I2C
                // * 传输设备子地址
                I2C_SendData(I2C_CBx->I2Cx, *I2C_CBx->CommCb.pData++);//EV8 just after EV6
                I2C_CBx->CommCb.iSize--;
            } else {    //* 读I2C数据
                if(I2C_CBx->CommCb.iSize == 1)               // * 接收数据为1个.
                    I2C_AcknowledgeConfig(I2C_CBx->I2Cx, DISABLE);          
                else 
                    I2C_AcknowledgeConfig(I2C_CBx->I2Cx, ENABLE);          
            }
            break;
        // * 在主模式下已传输完成(子地址/数据)
        case I2C_EVENT_MASTER_BYTE_TRANSMITTED:         // EV8
            if(I2C_CBx->CommCb.iSize > 0) {
                I2C_SendData(I2C_CBx->I2Cx, *I2C_CBx->CommCb.pData++);
                I2C_CBx->CommCb.iSize--;
            } else {
                I2C_GenerateSTOP(I2C_CBx->I2Cx, ENABLE);   //* 数据传输完毕,发送Stop condition
                // Post message tx over..
                OSMboxPost(I2C_CBx->pEventMB, (void *)MBOX_I2C_WRITE_DATA);
            }
            break;
        // * 在主模式下已接收完成
        case I2C_EVENT_MASTER_BYTE_RECEIVED:           // EV7
            *I2C_CBx->CommCb.pData++ = I2C_ReceiveData(I2C_CBx->I2Cx);
            I2C_CBx->CommCb.iSize--;
            if(I2C_CBx->CommCb.iSize == 1) { 
                I2C_AcknowledgeConfig(I2C_CBx->I2Cx, DISABLE);          //* 最后一个数据接收到后发送NACK
                                                                        // *下次发送非应答信号
            }
            if(I2C_CBx->CommCb.iSize == 0) {                        //* Send STOP Condition
                I2C_GenerateSTOP(I2C_CBx->I2Cx, ENABLE);
                OSMboxPost(I2C_CBx->pEventMB, (void *)MBOX_I2C_READ_DATA);
            }
            break;
        default:
            break;
    }    
}

//File         : I2CDev.h
//Created by   : Kuang Hao
#ifndef _I2CDEV_H_
#define _I2CDEV_H_

//* I2C通信控制块
typedef struct {
    INT8U bAddr;            //* 存储发送地址 
    INT32U iSize;           //* 存储写字节数 
    INT8U *pData;           //* 存储写的数据的指针 
    INT8U bDirection;       //* 数据传输方向
} tI2C_COMM_CB;      
//* I2C控制块
typedef struct {
    I2C_TypeDef *I2Cx;
    OS_EVENT *pEventSem;    // * Semaphore
    OS_EVENT *pEventMB;     // * Message box 
    tI2C_COMM_CB CommCb;
} tI2C_CB;     

#define I2C_COMM_TIMEOUT_TICKS    OS_TICKS_PER_SEC    
#define I2C_BUS_COUNT             2
#define I2C_OWN_ADDR_0          0xA2
#define I2C_OWN_ADDR_1          0xA2

#define MBOX_I2C_WRITE_SUB      1
#define MBOX_I2C_WRITE_DATA     2
#define MBOX_I2C_READ_DATA      3

#define I2C_EEPROM_ADDR         0xA0       //* CAT1025器件从地址    

extern tI2C_CB _I2CCtrlBlock[I2C_BUS_COUNT];
#define I2C_CB0     &_I2CCtrlBlock[0]
#define I2C_CB1     &_I2CCtrlBlock[1]
static void __InitI2CGPIO(void);
static void __InitI2CCB(void);
static INT8U __WriteI2CByte(tI2C_CB *I2C_CBx, 
                            INT8U bSlaveAddr, 
                            INT8U *bData, 
                            INT32U iDataSize, 
                            INT8U bDirection);
void InitI2C(u16 I2C0Addr, u16 I2C1Addr);
INT32U WriteI2CData(tI2C_CB *I2C_CBx, 
                    INT8U bSlaveAddr,   // * 从设备地址
                    INT8U *pData,       // * 写入的数据
                    INT32U iDataSize    // * 传输的数据长度,不包括子地址长度.
                   );
INT32U ReadI2CData(tI2C_CB *I2C_CBx, 
                   INT8U bSlaveAddr,   // * 从设备地址
                   INT16U iSubAddr,    // * 从设备子地址
                   INT8U bSubAddrLen,  // * 子地址长度 0 ~ 2
                   INT8U *pData,       // * 读取的数据
                   INT32U iDataSize    // * 传输的数据长度,不包括子地址长度.
                  );
void I2CIRQService(tI2C_CB *I2C_CBx);
#endif


 
沙发
FLandy| | 2007-9-27 13:19 | 只看该作者

波形

使用特权

评论回复
板凳
一览| | 2007-9-27 13:57 | 只看该作者

请仔细看manual

To close the communication: before reading the last byte from the I2Cn_DR register, set the
STOP bit to generate the Stop condition. The interface goes automatically back to slave mode
(M/SL bit cleared).


To close the communication: after writing the last byte to the I2Cn_DR register, set the STOP
bit to generate the Stop condition. 
The interface goes automatically back to slave mode (M/SLbit cleared).


STR912CPU对时序要求很严格,不按以上流程就会stop 无效。尤其是FA版本

使用特权

评论回复
地板
FLandy| | 2007-9-27 15:19 | 只看该作者

TO: 一览 谢了 问题解决了:)

中断中对EV7的处理做如下修改即可

        // * 在主模式下已接收完成
        case I2C_EVENT_MASTER_BYTE_RECEIVED:           // EV7
            if(I2C_CBx->CommCb.iSize == 1) {                        //* Send STOP Condition
                I2C_GenerateSTOP(I2C_CBx->I2Cx, ENABLE);
                OSMboxPost(I2C_CBx->pEventMB, (void *)MBOX_I2C_READ_DATA);
            }
            *I2C_CBx->CommCb.pData++ = I2C_ReceiveData(I2C_CBx->I2Cx);
            I2C_CBx->CommCb.iSize--;
            if(I2C_CBx->CommCb.iSize == 1) { 
                I2C_AcknowledgeConfig(I2C_CBx->I2Cx, DISABLE);          //* 最后一个数据接收到后发送NACK
                                                                        // *下次发送非应答信号
            }
            break;

使用特权

评论回复
5
yjf1979yjf| | 2007-9-27 16:42 | 只看该作者

用的东西真高档  我就用过10M的老式示波器

使用特权

评论回复
6
一览| | 2007-9-28 08:11 | 只看该作者

STR910芯片中断使用注意

STR910芯片的中断系统不是太完善,VIC0内的中断源优先级要高于VIC1内所有的中断源。中断优先级可以在同一个中断控制器内调准。please pay attention to this.

使用特权

评论回复
7
一览| | 2007-9-28 08:44 | 只看该作者

STR910芯片中断描述

Interrupt Priority
The FIQ interrupt has the highest priority and is followed by the 32 vectored interrupts. The
interrupt priority is based on the position of the vectored interrupt, where VIC0 Vectored
Interrupt 0 has the highest priority and VIC1 Vectored Interrupt 15 has the lowest priority. The
priority is hardwired and can not be changed.

使用特权

评论回复
8
Flandy|  楼主 | 2007-9-28 11:40 | 只看该作者

谢谢 提醒..

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

4

主题

17

帖子

1

粉丝