📄 i2c_hal.c
字号:
/* * * Copyright (c) Sigma Designs, Inc. 2002. All rights reserved. * *//** @file i2c.c @brief implemetation for I2C - using PIOs @author Aurelia Popa-Radu, Christian Wolff*/#include "../../../rmdef/rmdef.h"#include "../../../llad/include/gbus.h"#include "../../include/emhwlib_registers.h"#include "../include/i2c_hal.h"#define XTAL_REG (REG_BASE_system_block + SYS_xtal_in_cnt) // Location of the XTal counter register#define XTAL_MHZ 27 // XTal frequency (in MHz)#define ACK_TIMEOUT 10 // Waiting-for-Acknowlede Timeout, in uSec#define ARB_TIMEOUT 1000 // Arbitration Timeout, in uSec#define MASK_0 0x00010000#define MASK_1 0x00010001// --- time functionsstatic RMuint32 I2C_RM27MicroSecondElapsed(struct gbus* pGBus, RMuint32 t0){ RMuint32 t1; t1 = gbus_read_uint32(pGBus, XTAL_REG); if (t1 >= t0) return t1 - t0; else return 0xFFFFFFFF - t0 + t1 + 1;}static void I2C_RMMicroSecondSleep(struct gbus* pGBus, RMuint32 t0, RMuint32 us){ // implementation safe for delays smaller than 0xFFFFFFFF/27 us = 159 sec // if SYS_xtal_in_cnt doesn't work - hang here !! while (I2C_RM27MicroSecondElapsed(pGBus, t0) < XTAL_MHZ * us);}// --- media level functions with arbitration detection// all operations, on encountering an error, release the bus by tri-stating data and clockstatic RMstatus I2C_Clock(struct i2c* pI2C, RMbool clock){ RMuint32 t0; t0 = gbus_read_uint32(pI2C->pGBus, XTAL_REG); if (clock) { // read from clock line, wait until high gbus_write_uint32(pI2C->pGBus, pI2C->RegBase + SYS_gpio_dir, MASK_0 << pI2C->PioClock); // input while ((gbus_read_uint32(pI2C->pGBus, pI2C->RegBase + SYS_gpio_data) & (1 << pI2C->PioClock)) == 0) { if (I2C_RM27MicroSecondElapsed(pI2C->pGBus, t0) > XTAL_MHZ * ARB_TIMEOUT) { // timeout 1 ms // tri-state data and clock line gbus_write_uint32(pI2C->pGBus, pI2C->RegBase + SYS_gpio_dir, (MASK_0 << pI2C->PioData) | (MASK_0 << pI2C->PioClock)); // input return RM_TIMEOUT; } } } else { // write low to clock line gbus_write_uint32(pI2C->pGBus, pI2C->RegBase + SYS_gpio_data, MASK_0 << pI2C->PioClock); gbus_write_uint32(pI2C->pGBus, pI2C->RegBase + SYS_gpio_dir, MASK_1 << pI2C->PioClock); // output } if (pI2C->DelayUs) I2C_RMMicroSecondSleep(pI2C->pGBus, t0, pI2C->DelayUs); // The delay is too long but is not system dependent return RM_OK;}static RMstatus I2C_Data(struct i2c* pI2C, RMbool data){ RMuint32 t0; t0 = gbus_read_uint32(pI2C->pGBus, XTAL_REG); if (data) { // read from data line, wait until high gbus_write_uint32(pI2C->pGBus, pI2C->RegBase + SYS_gpio_dir, MASK_0 << pI2C->PioData); // input while ((gbus_read_uint32(pI2C->pGBus, pI2C->RegBase + SYS_gpio_data) & (1 << pI2C->PioData)) == 0) { if (I2C_RM27MicroSecondElapsed(pI2C->pGBus, t0) > XTAL_MHZ * ARB_TIMEOUT) { // timeout 1 ms // tri-state data and clock line gbus_write_uint32(pI2C->pGBus, pI2C->RegBase + SYS_gpio_dir, (MASK_0 << pI2C->PioData) | (MASK_0 << pI2C->PioClock)); // input return RM_TIMEOUT; } } } else { // write low to data line gbus_write_uint32(pI2C->pGBus, pI2C->RegBase + SYS_gpio_data, MASK_0 << pI2C->PioData); gbus_write_uint32(pI2C->pGBus, pI2C->RegBase + SYS_gpio_dir, MASK_1 << pI2C->PioData); // output } if (pI2C->DelayUs) I2C_RMMicroSecondSleep(pI2C->pGBus, t0, pI2C->DelayUs); // The delay is too long but is not system dependent return RM_OK;}// --- bit level functions// all operations, except Stop, end with Clock==low, blocking the bus for other mastersstatic RMstatus I2C_WrBit(struct i2c* pI2C, RMbool data){// send one bit// _// Ck _| |_// ___// Data X___X RMstatus err; if (RMFAILED(err = I2C_Data(pI2C, data))) return err; if (RMFAILED(err = I2C_Clock(pI2C, 1))) return err; if (RMFAILED(err = I2C_Clock(pI2C, 0))) return err; return RM_OK;}static RMstatus I2C_RdBit(struct i2c* pI2C, RMbool *data){// read one bit// _// Ck _| |_// ___// Data X___X RMstatus err; gbus_write_uint32(pI2C->pGBus, pI2C->RegBase + SYS_gpio_dir, MASK_0 << pI2C->PioData); // input if (RMFAILED(err = I2C_Clock(pI2C, 1))) return err; *data = (gbus_read_uint32(pI2C->pGBus, pI2C->RegBase + SYS_gpio_data) & (1 << pI2C->PioData)) ? 1 : 0; if (RMFAILED(err = I2C_Clock(pI2C, 0))) return err; return RM_OK;}static RMstatus I2C_Start( struct i2c* pI2C ){// Data goes high-to-low while Ck is high// ___// Ck _| |_// ___// Data |___ RMstatus err; // start sequence if (RMFAILED(err = I2C_Data(pI2C, 1))) return err; if (RMFAILED(err = I2C_Clock(pI2C, 1))) return err; if (RMFAILED(err = I2C_Data(pI2C, 0))) return err; if (RMFAILED(err = I2C_Clock(pI2C, 0))) return err; return RM_OK;}static RMstatus I2C_Stop( struct i2c* pI2C ){// Data goes low-to-high while Ck is high// __// Ck _|// _// Data __| RMstatus err; // stop sequence if (RMFAILED(err = I2C_Data(pI2C, 0))) return err; if (RMFAILED(err = I2C_Clock(pI2C, 1))) return err; if (RMFAILED(err = I2C_Data(pI2C, 1))) return err; return RM_OK;}static RMstatus I2C_SendNack(struct i2c* pI2C){// Not-Acknowledge from master// _// Ck _| |_// _____// Data return I2C_WrBit(pI2C, 1);}static RMstatus I2C_SendAck( struct i2c* pI2C ){// Acknowledge from master// _// Ck _| |_// // Data _____ return I2C_WrBit(pI2C, 0);}static RMstatus I2C_WaitAck( struct i2c* pI2C ){// __// Ck _| |_// // Data XX____ RMstatus err; RMuint32 t0; t0 = gbus_read_uint32(pI2C->pGBus, XTAL_REG); gbus_write_uint32(pI2C->pGBus, pI2C->RegBase + SYS_gpio_dir, MASK_0 << pI2C->PioData); // input if (RMFAILED(err = I2C_Clock(pI2C, 1))) return err; while (gbus_read_uint32(pI2C->pGBus, pI2C->RegBase + SYS_gpio_data) & (1 << pI2C->PioData)) { if (I2C_RM27MicroSecondElapsed(pI2C->pGBus, t0) > XTAL_MHZ * ACK_TIMEOUT) { // timeout 10 us // tri-state data and clock line gbus_write_uint32(pI2C->pGBus, pI2C->RegBase + SYS_gpio_dir, (MASK_0 << pI2C->PioData) | (MASK_0 << pI2C->PioClock)); // input return RM_TIMEOUT; } } if (RMFAILED(err = I2C_Clock(pI2C, 0))) return err; return RM_OK;}// --- byte level functionsstatic RMstatus I2C_WrByte(struct i2c* pI2C, RMuint8 ByteIn){// _ _ _ _ _ _ _ _// Ck _| |_| |_| |_| |_| |_| |_| |_| |_// ___ ___ ___ ___ ___ ___ ___ ___ // Data X___X___X___X___X___X___X___X___ RMuint32 i; RMstatus err; for (i = 0; i < 8; i++) { if (RMFAILED(err = I2C_WrBit(pI2C, ByteIn & 0x80))) return err; ByteIn <<= 1; } return RM_OK;}static RMstatus I2C_RdByte(struct i2c* pI2C, RMuint8 *data){// _ _ _ _ _ _ _ _// Ck _| |_| |_| |_| |_| |_| |_| |_| |_// ___ ___ ___ ___ ___ ___ ___ ___ // Data X___X___X___X___X___X___X___X___ RMuint32 i; RMbool bit; RMstatus err; for (i = 0; i < 8; i++) { if (RMFAILED(err = I2C_RdBit(pI2C, &bit))) return err; *data = (*data << 1) | (bit ? 1 : 0); } return RM_OK;}// --- externally available byte block functionsRMstatus I2C_Write(struct i2c* pI2C, RMuint8 SubAddress, RMuint8* pData, RMuint32 n){ RMuint32 i; RMstatus err; // Start,WrByte(WrAddress),WaitAck,WrByte(SubAddress),WaitAck, if (RMFAILED(err = I2C_Start(pI2C))) return err; if (RMFAILED(err = I2C_WrByte(pI2C, pI2C->WrAddr))) return err; if (RMFAILED(err = I2C_WaitAck(pI2C))) return err; if (RMFAILED(err = I2C_WrByte(pI2C, SubAddress))) return err; if (RMFAILED(err = I2C_WaitAck(pI2C))) return err; // if not last byte repeat(WrByte,WaitAck),Stop for (i = 0; i < n; i++) { if (RMFAILED(err = I2C_WrByte( pI2C, pData[i]))) return err; if (RMFAILED(err = I2C_WaitAck(pI2C))) return err; } if (RMFAILED(err = I2C_Stop(pI2C))) return err; return RM_OK;}RMstatus I2C_Read(struct i2c* pI2C, RMuint8 SubAddress, RMuint8* pData, RMuint32 n){ RMuint32 i; RMstatus err; if (n < 1) return RM_ERROR; // Start,WrByte(WrAddress),WaitAck,WrByte(SubAddress),WaitAck, if (RMFAILED(err = I2C_Start(pI2C))) return err; if (RMFAILED(err = I2C_WrByte(pI2C, pI2C->WrAddr))) return err; if (RMFAILED(err = I2C_WaitAck(pI2C))) return err; if (RMFAILED(err = I2C_WrByte(pI2C, SubAddress))) return err; if (RMFAILED(err = I2C_WaitAck(pI2C))) return err; // Start,WrByte(RdAddress),WaitAck, if (RMFAILED(err = I2C_Start(pI2C))) return err; if (RMFAILED(err = I2C_WrByte(pI2C, pI2C->RdAddr))) return err; if (RMFAILED(err = I2C_WaitAck(pI2C))) return err; // if not last byte repeat(RdByte,Ack),RdByte(last),Nack,Stop for (i = 0; i < n; i++) { if (RMFAILED(err = I2C_RdByte(pI2C, &(pData[i])))) return err; if (i == (n - 1)) { if (RMFAILED(err = I2C_SendNack(pI2C))) return err; } else { if (RMFAILED(err = I2C_SendAck(pI2C))) return err; } } if (RMFAILED(err = I2C_Stop(pI2C))) return err; return RM_OK;}RMstatus I2C_Write_NoSubAddr(struct i2c* pI2C, RMuint8* pData, RMuint32 n){ RMuint32 i; RMstatus err; if (RMFAILED(err = I2C_Start(pI2C))) return err; if (RMFAILED(err = I2C_WrByte(pI2C, pI2C->WrAddr))) return err; if (RMFAILED(err = I2C_WaitAck(pI2C))) return err; for (i = 0; i < n; i++) { if (RMFAILED(err = I2C_WrByte(pI2C, pData[i]))) return err; if (RMFAILED(err = I2C_WaitAck(pI2C))) return err; } if (RMFAILED(err = I2C_Stop(pI2C))) return err; return RM_OK;}RMstatus I2C_Read_NoSubAddr(struct i2c* pI2C, RMuint8* pData, RMuint32 n){ RMuint32 i; RMstatus err; if (n < 1) return RM_ERROR; if (RMFAILED(err = I2C_Start(pI2C))) return err; if (RMFAILED(err = I2C_WrByte(pI2C, pI2C->RdAddr))) return err; if (RMFAILED(err = I2C_WaitAck(pI2C))) return err; for (i = 0; i < n; i++) { if (RMFAILED(err = I2C_RdByte(pI2C, &(pData[i])))) return err; if (i == (n - 1)) { if (RMFAILED(err = I2C_SendNack(pI2C))) return err; } else { if (RMFAILED(err = I2C_SendAck(pI2C))) return err; } } if (RMFAILED(err = I2C_Stop(pI2C))) return err; return RM_OK;}RMstatus I2C_Select_Segment( struct i2c* pI2C, RMuint8 SegmentAddr, RMuint8 Segment ){ RMstatus err; if (RMFAILED(err = I2C_Start(pI2C))) return err; if (RMFAILED(err = I2C_WrByte(pI2C, SegmentAddr))) return err; if (RMFAILED(err = I2C_WaitAck(pI2C))) return err; if (RMFAILED(err = I2C_WrByte(pI2C, Segment))) return err; if (RMFAILED(err = I2C_WaitAck(pI2C))) return err; return RM_OK;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -