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

📄 i2c.c

📁 本程序为ST公司开发的源代码
💻 C
字号:
/************************************************** * * i2c.c * * CVS ID:   $Id: i2c.c,v 1.11 2007/10/25 10:11:58 marcucci Exp $ * Author:   Maurizio Marcucci [MM] - STM * Date:     $Date: 2007/10/25 10:11:58 $ * Revision: $Revision: 1.11 $ *  * Description: *  *   Low level I2C driver * *************************************************** *  * COPYRIGHT (C) ST Microelectronics  2005 *            All Rights Reserved * *************************************************** * * STM CVS Log: * * $Log: i2c.c,v $ * Revision 1.11  2007/10/25 10:11:58  marcucci * Enable SCL & SDA I2C lines only after complete I2C Hardware initilaization * * Revision 1.10  2007/10/12 13:17:42  marcucci * I2C interrupts procedure modifed to work at 400Khz and put a control to * avoid that Received bytes exceed the I2c buffer size * * Revision 1.9  2007/05/02 12:42:50  belardi * Fix for race condition between hostif and i2c driver that cause loss of host command reception in presence of frequent CRQ timeout * * Revision 1.8  2006/12/19 17:06:00  belardi * Sends 0x00 if host requests more bytes than available in current packet * * Revision 1.7  2006/10/18 12:38:44  belardi * Removed USE_STM_HOSTIF * * Revision 1.6  2006/09/18 09:55:23  belardi * Corrected CVS keyword usage * * Revision 1.5  2006/09/18 09:24:13  belardi * Added Log CVS keyword into file header * * ***************************************************/#include "gendef.h"#include "hwreg.h"#include "osal.h"#include "utility.h"#include "accordoptimer.h"#include "i2c.h"#include "player.h"#include "hostif_low.h"#include "hostif_high.h"#define RWBIT_MASK 0x01I2C_FLAGS_STRUCT i2c_flags;/* Link layer message buffer for send and receive functions */char i2c_irq_rx_buffer[DEFAULT_MAX_I2C_FRAME_SIZE];uint16 i2c_irq_rx_buffer_idx;char i2c_irq_tx_buffer[DEFAULT_MAX_I2C_FRAME_SIZE];uint16 i2c_irq_tx_buffer_idx;void i2c_event_isr(void);/******************************************************************************//* Function:  i2c_soft_reset                                                  *//*                                                                            *//*! \brief    Initialize the I2C flags  *  \param    void *  \return   void *  \remark *//******************************************************************************/void i2c_soft_reset(void){ uint32 i; i2c_flags.i2c_rx_ready = 1; i2c_flags.i2c_new_cmd = 0; i2c_irq_rx_buffer_idx = 0; /* Initialize the buffers, only for debug */ for(i = 0; i < DEFAULT_MAX_I2C_FRAME_SIZE; i++) {  i2c_irq_rx_buffer[i] = 0x00; } i2c_soft_reset_tx();}/******************************************************************************//* Function:  i2c_soft_reset_tx                                               *//*                                                                            *//*! \brief    Initialize the I2C flags fot tx direction only *  \param    void *  \return   void *  \remark *//******************************************************************************/void i2c_soft_reset_tx(void){ uint32 i; i2c_flags.i2c_tx_ready = 1; i2c_flags.tx_msg_done = 1; i2c_irq_tx_buffer_idx = 0; /* Initialize the buffers, only for debug */ for(i = 0; i < DEFAULT_MAX_I2C_FRAME_SIZE; i++) {  i2c_irq_tx_buffer[i] = 0x00; } /* Set I2C CRQ line to inactive */ PDB |= I2C_CRQ_OR_MASK;}/******************************************************************************//* Function:  i2c_init                                                        *//*                                                                            *//*! \brief    Initialize the I2C hardware  *  \param    void *  \return   void *  \remark *//******************************************************************************/void i2c_init(void){ uint32 dummy;  i2c_soft_reset();  I2C0_CR.all = 0; /* Configure Frequency Bits to match I2C setup/hold times */ I2C0_OAR2.field.fr = 6;   // Input Frequency 66-80Mhz// I2C0_CCR.field.fm_sm = 0; // Standard I2C // I2C0_CCR.field.cc_0_6 = 0x32; // 10Khz I2C// I2C0_ECCR = 0x1A; /* Clock Control Register */ I2C0_CCR.field.fm_sm = 1; // Fast I2C I2C0_CCR.field.cc_0_6 = 0x6E; // 100Khz I2C  0xde = 100Khz                               // 200Khz I2C  0x6E = 200Khz /* Extended Clock Control Register */ /* set the clock divider along with I2C_CCR register */ I2C0_ECCR = 0x00;  /* Peripheral Enable */ /* Repeated write to pe bit is required! */ I2C0_CR.field.pe = 1; I2C0_CR.field.pe = 1;  /* Enable General Call (I2C address 0x00) */ /* This is not requires by CIS, should we delete it? */ I2C0_CR.field.engc = 1; I2C0_CR.field.ack = 1; /* Own Address Register*/ I2C0_OAR1 = 0; I2C0_OAR1 = I2C_SLAVE_ADDRESS; /* High bits of Own Address - used for 10 bit addressing */ I2C0_OAR2.field.add_8_9 = 0; OSAL_isr_install(OSAL_ISR_I2C0_EVENT, 0x0f, i2c_event_isr);// [RB] use the same handler for both interupt sources// [RB] This is not an error, see remarks in i2c_event_isr() OSAL_isr_install(OSAL_ISR_I2C0_DATA, 0x0f, i2c_event_isr);  /* wait for I2C bus to be idle (why?) */ //while(I2C0_SR1.field.busy) dummy = I2C0_SR1.all; dummy = I2C0_SR2.all;      /* Interrupt Enable */ I2C0_CR.field.ite = 1; //configure_gpio(PORT_B, GPIO_2, GPIO_AF_PP); // use GPIO_AF_PP for I2C SCL //configure_gpio(PORT_B, GPIO_3, GPIO_AF_PP); // use GPIO_AF_PP for I2C SDA // Do I2C Cell Initialization with SDA and SCL pins not connected to the I2C // Hardware cell. // Connect the SDA and SCL pin to the I2C Hardware cell only after its complete // initialization DISABLE_INTERRUPTS(); PC0B |= 0x000C; PC1B |= 0x000C; PC2B |= 0x000C; ENABLE_INTERRUPTS()}/******************************************************************************//* Function:  i2c_event_isr                                          *//*                                                                            *//*! \brief    I2C interrupt handler, event  *  \param    void *  \return   void *  \remark   This version works around a hardware 'feature': sometimes the *            "i2c byte transfer" interrupt on the last byte of a tx happens before *            the "i2c event" interrupt. As a consequence, the Ack Failure condition *            is not processed correctly and the Accordo+ does not release the *            SDA line. *            The workaround is to process both interrupt sources in the same *            handler, to make sure that the AF condition is checked before *            the byte transfer isntruction that resets the SDA line. *            Since OS20 enables irq during interrupt processing, it is necessary *            to disable interrupts in this handler, because it is not reentrant. *//******************************************************************************/void i2c_event_isr(void){ I2C_SR1_UNION i2c_sr1; I2C_SR2_UNION i2c_sr2; uint8 i2c_slave_addr; uint8 i2c_dummy_reg;  DISABLE_INTERRUPTS();  i2c_sr1.all = I2C0_SR1.all; i2c_sr2.all = I2C0_SR2.all; //[MM]: In case of Slave Transmitter, Master Send NACK after reciving //      Last Data Byte. It could happen that Stop interrupts was lost because //      stop flag was set in I2C0_SR2 register but I2C_SR1.evf flag was not set. //if(i2c_sr1.field.evf) //{   if(i2c_sr1.field.adsl)  {    start_timer(HOSTIF_LL_STOP_TIMER, HOSTIF_LL_STOP_TIMER_DURATION);   // Start Condition    // Good Slave Address Detected   // Reset I2C Flags.       i2c_flags.af = 0;    if(i2c_flags.i2c_tx_ready == 0)    {     // Start received while I2C Transmitter is active.     // It is Stop Condition     // Repeated Start Condition     i2c_flags.i2c_tx_ready = 1;     /* [RB] signal to application that the tx buffer is ready */     i2c_flags.tx_msg_done = 1;     /* release the CRQ line (set high) */     PDB |= I2C_CRQ_OR_MASK;     stop_timer(HOSTIF_LL_CRQ_TIMER);     hostif_inevent |= HOSTIF_EVT_LL_TX_COMPLETE;      OSAL_wake_thread(OSAL_THREAD_HostIfTask);    }        if(i2c_flags.i2c_rx_ready == 0)    {     // Start received while I2C Receiver is active.     // It is Stop Condition     // Repeated Start Condition     i2c_flags.i2c_rx_ready = 1;     hostif_inevent |= HOSTIF_EVT_LL_NEW_MSG;     OSAL_wake_thread(OSAL_THREAD_HostIfTask);    }    /* First data byte after I2C Start condition */    /* is the address, read to check if it is a read or write */    i2c_slave_addr = I2C0_DR;    if(i2c_slave_addr & RWBIT_MASK)    {     // Slave Transmitter (Read Condition)     i2c_irq_tx_buffer_idx = 0;     i2c_flags.i2c_tx_ready = 0;     /* release the CRQ line (set high) */     PDB |= I2C_CRQ_OR_MASK;     stop_timer(HOSTIF_LL_CRQ_TIMER);    }    else    {     // Slave Receiver (Write Condition)     i2c_irq_rx_buffer_idx = 0;     i2c_flags.i2c_rx_ready = 0;    }  }//if(i2c_sr1.field.adsl)  else if (i2c_sr2.field.af == 1)  {    // Acknowledgement Failure    i2c_flags.af = 1;    //[MM]: As I2C specification Master send NACK and then it sent STOP.    //      Master can decide to read a quantity of data different from     //      what the Message Length says. This is not an error.    //if (i2c_irq_tx_buffer_idx != i2c_irq_tx_buffer[0] + 1)    //{	//	//hostif_inevent |= HOSTIF_EVT_LL_AF_ERR;	//	//OSAL_wake_thread(OSAL_THREAD_HostIfTask);    //}  }  else  {    if (i2c_sr2.field.stopf)   {    stop_timer(HOSTIF_LL_STOP_TIMER);    // Stop Condition Detected    if(i2c_flags.i2c_rx_ready == 0)    {      // Message Reception On Going      i2c_flags.i2c_rx_ready = 1; // Release Receiver      hostif_inevent |= HOSTIF_EVT_LL_NEW_MSG;      OSAL_wake_thread(OSAL_THREAD_HostIfTask);    }    if(i2c_flags.i2c_tx_ready == 0)    {     i2c_flags.i2c_tx_ready = 1;     /* [RB] signal to application that the tx buffer is ready */     i2c_flags.tx_msg_done = 1;     hostif_inevent |= HOSTIF_EVT_LL_TX_COMPLETE;     OSAL_wake_thread(OSAL_THREAD_HostIfTask);    }   }  } //}  /* The i2c_xfer_isr interrupt handler began here */  /* Byte Transfer Finished */ if(i2c_sr1.field.btf == 1) {  /* TRA field provides info on the direction of the transfer */  if(i2c_sr1.field.tra == 1)  {   // Send Bytes   if(i2c_flags.af == 0)   {    if(i2c_irq_tx_buffer_idx < i2c_irq_tx_buffer[0] + 1)    {     I2C0_DR = i2c_irq_tx_buffer[i2c_irq_tx_buffer_idx];     i2c_irq_tx_buffer_idx++;    }    else    {     I2C0_DR = 0x00;    }        }   else   {    /* Acknowledge Failure error condition: release the SDA lines */    /* See datasheet Page 220 */    I2C0_DR = 0xFF;   }  }  else  {   // [MM] Discard Data exceeding the size of I2C reciving Buffer   if(i2c_irq_rx_buffer_idx < DEFAULT_MAX_I2C_FRAME_SIZE)   {    i2c_irq_rx_buffer[i2c_irq_rx_buffer_idx++] = I2C0_DR;    }   else   {    i2c_dummy_reg = I2C0_DR;   }   } }  ENABLE_INTERRUPTS();}

⌨️ 快捷键说明

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