📄 twi.c
字号:
/* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support
* ----------------------------------------------------------------------------
* Copyright (c) 2008, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ----------------------------------------------------------------------------
*/
#ifndef trace_LEVEL
#define trace_LEVEL 1
#endif
//------------------------------------------------------------------------------
// Headers
//------------------------------------------------------------------------------
#include "twi.h"
#include <pio/pio.h>
#include <pmc/pmc.h>
#include <utility/math.h>
#include <utility/assert.h>
#include <utility/trace.h>
#define TWI_CLOCK 100000
#define ERROR (AT91C_TWI_NACK_SLAVE) //状态寄存器的一位,如果置1表示从机未应答
//------------------------------------------------------------------------------
// Global functions
//------------------------------------------------------------------------------
//*=============================================================================
//* \fn AT91F_TWI_CfgPIO
//* \brief Configure PIO controllers to drive TWI signals
//*=============================================================================
void TWI_CfgPIO (void)
{
// Configure PIO controllers to periph mode
PIO_CfgPeriph(AT91C_BASE_PIOA, // PIO controller base address
((unsigned int) AT91C_PA23_TWD ) |
((unsigned int) AT91C_PA24_TWCK ), // Peripheral A
0); // Peripheral B
}
//*=============================================================================
//* 函数名称:TWI_Configure
//* 函数功能:配置 TWI 时钟及模式
//* 入口参数:1. twck: TWI 指针
//* 2. mck : 系统主频
//* 返回值 :无
//*=============================================================================
void TWI_Configure(AT91S_TWI *pTwi, unsigned int twck, unsigned int mck)
{
unsigned int ckdiv = 0;
unsigned int cldiv;
unsigned char ok = 0;
trace_LOG(trace_DEBUG, "-D- TWI_Configure()\r\n");
SANITY_CHECK(pTwi);
// Reset the TWI
pTwi->TWI_CR = AT91C_TWI_SWRST;
// Set master mode
pTwi->TWI_CR = AT91C_TWI_MSEN;
// Configure clock
while (!ok)
{
cldiv = ((mck / (2 * twck)) - 3) / power(2, ckdiv);
if (cldiv <= 255)
ok = 1;
else
ckdiv++;
}
ASSERT(ckdiv < 8, "-F- Cannot find valid TWI clock parameters\r\n");
//trace_LOG(trace_INFO, "-D- Using CKDIV = %u and CLDIV/CHDIV = %u\r\n", ckdiv, cldiv);
pTwi->TWI_CWGR = (ckdiv << 16) | (cldiv << 8) | cldiv;
}
//*----------------------------------------------------------------------------
//* \fn AT91F_TWI_Configure
//* \brief Configure TWI in master mode
//*----------------------------------------------------------------------------
void AT91F_TWI_Configure ( AT91PS_TWI pTWI ) // \arg pointer to a TWI controller
{
//* Disable interrupts
pTWI->TWI_IDR = (unsigned int) -1;
//* Reset peripheral
pTWI->TWI_CR = AT91C_TWI_SWRST;
//* Set Master mode
pTWI->TWI_CR = AT91C_TWI_MSEN;
}
//*============================================================================
//* TWI初始化
//*============================================================================
//*============================================================================
//* 函数名称:AT91F_SetTwiClock
//* 函数功能:设置TWI时钟
//* 入口参数:无
//* 返回值 :无
//*============================================================================
void AT91F_SetTwiClock(const AT91PS_TWI pTwi)
{
int sclock;
/* Here, CKDIV = 1 and CHDIV=CLDIV ==> CLDIV = CHDIV = 1/4*((Fmclk/FTWI) -6)*/
sclock = (10*BOARD_MCK / TWI_CLOCK);
if (sclock % 10 >= 5)
sclock = (sclock /10) - 5;
else
sclock = (sclock /10)- 6;
sclock = (sclock + (4 - sclock %4)) >> 2; // div 4
pTwi->TWI_CWGR = 0x00010000 | sclock | (sclock << 8);
}
//*============================================================================
//* 函数名称: TWI_Open
//* 函数功能: 打开 TWI
//*============================================================================
void TWI_Open(void)
{
// 配制 PIO 为 TWI
TWI_CfgPIO ();
PIO_CfgOpendrain(AT91C_BASE_PIOA, AT91C_PA23_TWD | AT91C_PA24_TWCK); //配制 PA23,PA24 为开漏
// 使能 TWI 电源时钟
PMC_EnablePeripheral(AT91C_ID_TWI );
// 配制 TWI 为主模式
TWI_Configure (AT91C_BASE_TWI, TWI_CLOCK, BOARD_MCK);
}
//*============================================================================
//* 函数名称: AT91F_TWI_Close
//* 函数功能: 关闭 TWI
//*============================================================================
void TWI_Close(void)
{
// 禁用 TWI 电源时钟
PMC_DisablePeripheral( AT91C_ID_TWI );
}
//*=============================================================================
//* 函数名称:TWI_Stop
//* 函数功能:发送停止位
//* 入口参数:1. twck: TWI 指针
//* 返回值 :无
//*=============================================================================
void TWI_Stop(AT91S_TWI *pTwi)
{
SANITY_CHECK(pTwi);
pTwi->TWI_CR = AT91C_TWI_STOP;
}
//------------------------------------------------------------------------------
/// Starts a read operation on the TWI bus with the specified slave, and returns
/// immediately. Data must then be read using TWI_ReadByte() whenever a byte is
/// available (poll using TWI_ByteReceived()).
/// \param pTwi Pointer to an AT91S_TWI instance.
/// \param address Slave address on the bus.
/// \param iaddress Optional internal address bytes.
/// \param isize Number of internal address bytes.
//-----------------------------------------------------------------------------
void TWI_StartRead( AT91S_TWI *pTwi,
unsigned char address,
unsigned int iaddress,
unsigned char isize)
{
trace_LOG(trace_DEBUG, "-D- TWI_StartRead()\n\r");
SANITY_CHECK(pTwi);
SANITY_CHECK((address & 0x80) == 0);
SANITY_CHECK((iaddress & 0xFF000000) == 0);
SANITY_CHECK(isize < 4);
// Set slave address and number of internal address bytes
pTwi->TWI_MMR = (isize << 8) | AT91C_TWI_MREAD | (address << 16);
// Set internal address bytes
pTwi->TWI_IADR = iaddress;
// Send START condition
pTwi->TWI_CR = AT91C_TWI_START;
}
//-----------------------------------------------------------------------------
/// Reads a byte from the TWI bus. The read operation must have been started
/// using TWI_StartRead() and a byte must be available (check with
/// TWI_ByteReceived()).
/// Returns the byte read.
/// \param pTwi Pointer to an AT91S_TWI instance.
//-----------------------------------------------------------------------------
unsigned char TWI_ReadByte(AT91S_TWI *pTwi)
{
SANITY_CHECK(pTwi);
return pTwi->TWI_RHR;
}
//-----------------------------------------------------------------------------
/// Sends a byte of data to one of the TWI slaves on the bus. This function
/// must be called once before TWI_StartWrite() with the first byte of data
/// to send, then it shall be called repeatedly after that to send the
/// remaining bytes.
/// \param pTwi Pointer to an AT91S_TWI instance.
/// \param byte Byte to send.
//-----------------------------------------------------------------------------
void TWI_WriteByte(AT91S_TWI *pTwi, unsigned char byte)
{
SANITY_CHECK(pTwi);
pTwi->TWI_THR = byte;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -