/*! * COPYRIGHT NOTICE * Copyright (c) 2013,山外科技 * All rights reserved. * 技术讨论:山外论坛 http://www.vcan123.com * * 除注明出处外,以下所有内容版权均属山外科技所有,未经允许,不得用于商业用途, * 修改内容时必须保留山外科技的版权声明。 * * @file MK60_i2c.c * @brief i2c驱动函数 * @author 山外科技 * @version v5.0 * @date 2013-07-12 */ #include "common.h" #include "MK60_port.h" #include "MK60_i2c.h" unsigned char MasterTransmission; unsigned char SlaveID; I2C_MemMapPtr I2CN[2] = {I2C0_BASE_PTR, I2C1_BASE_PTR}; //定义两个指针数组保存 I2CN 的地址 /* * 把I2C通信的每个小步骤都用宏定义来实现,方便编写顶层函数 * 此宏定义参考飞思卡尔公司例程修改所得 */ //启动信号 #define i2c_Start(I2Cn) I2C_C1_REG(I2CN[I2Cn]) |= (I2C_C1_TX_MASK | I2C_C1_MST_MASK) //MST 由0变1,产生起始信号,TX = 1 进入发送模式 //停止信号 #define i2c_Stop(I2Cn) I2C_C1_REG(I2CN[I2Cn]) &= ~(I2C_C1_MST_MASK | I2C_C1_TX_MASK) //MST 由1变0,产生停止信号,TX = 0 进入接收模式 //重复启动 #define i2c_RepeatedStart(I2Cn) I2C_C1_REG(I2CN[I2Cn]) |= I2C_C1_RSTA_MASK //进入接收模式(应答,需要接收多个数据,接收最后一个字节前需要禁用应答i2c_DisableAck) #define i2c_EnterRxMode(I2Cn) I2C_C1_REG(I2CN[I2Cn]) &= ~(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK) // //进入接收模式(不应答,只接收一个字节) #define i2c_PutinRxMode(I2Cn) I2C_C1_REG(I2CN[I2Cn]) &= ~I2C_C1_TX_MASK;I2C_C1_REG(I2CN[I2Cn]) |= I2C_C1_TXAK_MASK //禁用应答(接收最后一个字节) #define i2c_DisableAck(I2Cn) I2C_C1_REG(I2CN[I2Cn]) |= I2C_C1_TXAK_MASK //等待 I2C_S #define i2c_Wait(I2Cn) while(( I2C_S_REG(I2CN[I2Cn]) & I2C_S_IICIF_MASK)==0) {} \ I2C_S_REG(I2CN[I2Cn]) |= I2C_S_IICIF_MASK; //写一个字节 #define i2c_write_byte(I2Cn,data) (I2C_D_REG(I2CN[I2Cn]) = (data));i2c_Wait(I2Cn) /*! * @brief I2C初始化,设置波特率 * @param I2Cn_e I2C模块(I2C0、I2C1) * @param baud 期待的波特率 * @return 实际的波特率 * @since v5.0 * Sample usage: i2c_init(I2C0,400*1000); // 初始化I2C0,期待的波特率为400k */ uint32 i2c_init(I2Cn_e i2cn, uint32 baud) { if(i2cn == I2C0) { /* 开启时钟 */ #if defined(MK60DZ10) SIM_SCGC4 |= SIM_SCGC4_I2C0_MASK; //开启 I2C0时钟 #elif defined( MK60F15) SIM_SCGC4 |= SIM_SCGC4_IIC0_MASK; //开启 I2C0时钟 #endif /* 配置 I2C0功能的 GPIO 接口 */ if((I2C0_SCL_PIN == PTB0) || (I2C0_SCL_PIN == PTB2) || (I2C0_SCL_PIN == PTD8) ) { port_init (I2C0_SCL_PIN, ALT2 | ODO | PULLUP ); } else ASSERT(0); //上诉条件都不满足,直接断言失败了,设置管脚有误? if((I2C0_SDA_PIN == PTB1) || (I2C0_SDA_PIN == PTB3) || (I2C0_SDA_PIN == PTD9) ) port_init (I2C0_SDA_PIN, ALT2 | ODO | PULLUP ); else ASSERT(0); //上诉条件都不满足,直接断言失败了,设置管脚有误? } else { /* 开启时钟 */ #if defined(MK60DZ10) SIM_SCGC4 |= SIM_SCGC4_I2C1_MASK; //开启 I2C1时钟 #elif defined(MK60F15) SIM_SCGC4 |= SIM_SCGC4_IIC1_MASK; //开启 I2C1时钟 #endif /* 配置 I2C1功能的 GPIO 接口 */ if(I2C1_SCL_PIN == PTE1) port_init (I2C1_SCL_PIN, ALT6 | ODO | PULLUP ); else if(I2C1_SCL_PIN == PTC10) port_init (I2C1_SCL_PIN, ALT2 | ODO | PULLUP ); else ASSERT(0); //上诉条件都不满足,直接断言失败了,设置管脚有误? if(I2C1_SDA_PIN == PTE0) port_init (I2C1_SDA_PIN, ALT6 | ODO | PULLUP ); else if (I2C1_SDA_PIN == PTC11) port_init (I2C1_SDA_PIN, ALT2 | ODO | PULLUP ); else ASSERT(0); //上诉条件都不满足,直接断言失败了,设置管脚有误? } /* 设置频率 */ // I2C baud rate = bus speed (Hz)/(mul × SCL divider) 即这里 50MHz/(1 ×128)=390.625kHz // SDA hold time = bus period (s) × mul × SDA hold value // SCL start hold time = bus period (s) × mul × SCL start hold value // SCL stop hold time = bus period (s) × mul × SCL stop hold value //查表 ICR 对应的 SCL_divider ,见 《K60P144M100SF2RM.pdf》第1468页的 I2C Divider and Hold Values uint16 ICR_2_SCL_divider[0x40] = { 20, 22, 24, 26, 28, 30, 34, 40, 28, 32, 36, 40, 44, 48, 56, 68, 48, 56, 64, 72, 80, 88, 104, 128, 80, 96, 112, 128, 144, 160, 192, 240, 160, 192, 224, 256, 288, 320, 384, 480, 320, 384, 448, 512, 576, 640, 768, 960, 640, 768, 896, 1024, 1152, 1280, 1536, 1920, 1280, 1536, 1792, 2048, 2304, 2560, 3072, 3840 }; uint8 mult; if(bus_clk_khz <= 50000)mult = 0; //bus 一分频 else if(bus_clk_khz <= 100000)mult = 1; //bus 二分频 else mult = 2; //bus 四分频 uint16 scldiv = bus_clk_khz * 1000 / ( (1<