#include "include.h" #define TRACE_EN 0 #if TRACE_EN #define TRACE(...) printf(__VA_ARGS__) #define TRACE_K(...) printk(__VA_ARGS__) #else #define TRACE(...) #define TRACE_K(...) #endif #if I2C_SW_EN //AT(.text.bsp.i2c) //static void bsp_i2c_delay(void) //{ // u8 delay = 60; // while (delay--) { // asm("nop"); // } //} #define bsp_i2c_delay() delay_us(5) //ACK: The transmitter releases the SDA line (HIGH->LOW) during the acknowledge clock pulse AT(.text.bsp.i2c) void bsp_i2c_tx_ack(void) { I2C_SDA_OUT(); I2C_SDA_L(); bsp_i2c_delay(); I2C_SCL_H(); bsp_i2c_delay(); I2C_SCL_L(); } AT(.text.bsp.i2c) bool bsp_i2c_rx_ack(void) { bool ret = false; I2C_SDA_IN(); bsp_i2c_delay(); I2C_SCL_H(); bsp_i2c_delay(); if (!I2C_SDA_IS_H()) { ret = true; } I2C_SCL_L(); return ret; } //NACK: The transmitter holds the SDA line (keep HIGH) during the acknowledge clock pulse AT(.text.bsp.i2c) void bsp_i2c_tx_nack(void) { I2C_SDA_OUT(); I2C_SDA_H(); bsp_i2c_delay(); I2C_SCL_H(); bsp_i2c_delay(); I2C_SCL_L(); } //START: A HIGH to LOW transition on the SDA line while SCL is HIGH is one such unique case. AT(.text.bsp.i2c) void bsp_i2c_start(void) { I2C_SDA_SCL_OUT(); I2C_SDA_SCL_H(); bsp_i2c_delay(); I2C_SDA_L(); bsp_i2c_delay(); I2C_SCL_L(); } //STOP: A LOW to HIGH transition on the SDA line while SCL is HIGH AT(.text.bsp.i2c) void bsp_i2c_stop(void) { I2C_SDA_OUT(); I2C_SDA_L(); bsp_i2c_delay(); I2C_SCL_H(); bsp_i2c_delay(); I2C_SDA_H(); } //tx 1byte AT(.text.bsp.i2c) void bsp_i2c_tx_byte(uint8_t dat) { u8 i; I2C_SDA_OUT(); for (i=0; i<8; i++) { if (dat & BIT(7)) { I2C_SDA_H(); } else { I2C_SDA_L(); } bsp_i2c_delay(); I2C_SCL_H(); bsp_i2c_delay(); I2C_SCL_L(); dat <<= 1; } } //rx 1byte AT(.text.bsp.i2c) uint8_t bsp_i2c_rx_byte(void) { u8 i, dat = 0; I2C_SDA_IN(); for (i=0; i<8; i++) { bsp_i2c_delay(); I2C_SCL_H(); bsp_i2c_delay(); dat <<= 1; if (I2C_SDA_IS_H()) { dat |= BIT(0); } I2C_SCL_L(); } return dat; } #endif //I2C_SW_EN #if I2C_HW_EN void bsp_i2c0_lock(void) { os_i2c0_lock(100); } void bsp_i2c0_unlock(void) { os_i2c0_unlock(); } AT(.com_text.isr.i2c) void bsp_i2c_isr(void) { if (IIC0CON0 & BIT(31)) { IIC0CON0 |= BIT(29); // clear pending IIC0CON0 &= ~BIT(1); // disable irq IIC0DMACNT = 0; // Disable DMA } } static u32 bsp_hw_i2c_config(u32 i2c_cfg, u16 dev_addr, u16 reg_addr, u32 dat) { TRACE("%s: cfg=%X dev=%X reg=%X\n", __FUNCTION__, i2c_cfg, dev_addr, reg_addr); IIC0CMDA = (u8)dev_addr | ((u32)(dev_addr >> 8)) << 24 | (u32)((u8)reg_addr) << 8 | (u32)((u8)(reg_addr >> 8)) << 16; IIC0CON1 = i2c_cfg; IIC0DATA = dat; IIC0CON0 |= BIT(28); // kick u32 ticks = tick_get(); while ( (!(IIC0CON0 & BIT(31)))) { if (tick_check_expire(ticks, 20)) { printf("IIC ERROR\n"); return false; } } IIC0CON0 |= BIT(29); if (i2c_cfg & RDATA) { return IIC0DATA; } else { return true; } } void bsp_hw_i2c_tx_byte(u32 i2c_cfg, u16 dev_addr, u16 reg_addr, u32 data) { bsp_i2c0_lock(); bsp_hw_i2c_config(i2c_cfg, dev_addr, reg_addr, data); bsp_i2c0_unlock(); } void bsp_hw_i2c_tx_buf(u32 i2c_cfg, u16 dev_addr, u16 reg_addr, u8 *buf, u16 len) { int i; u32 cfg; if (buf == NULL || len == 0) { return; } bsp_i2c0_lock(); for (i = 0; i < len; i++) { cfg = WDATA; if (i == 0) { //收第1byte cfg |= i2c_cfg; } if (i == (len - 1)) { //收最后1byte cfg |= STOP_FLAG; } bsp_hw_i2c_config(cfg | DATA_CNT_1B, dev_addr, reg_addr, buf[i]); } bsp_i2c0_unlock(); } void bsp_hw_i2c_rx_buf(u32 i2c_cfg, u16 dev_addr, u16 reg_addr, u8 *buf, u16 len) { int i; u32 cfg; if (buf == NULL || len == 0) { return; } bsp_i2c0_lock(); for (i = 0; i < len; i++) { cfg = RDATA; if (i == 0) { //收第1byte cfg |= i2c_cfg; } if (i == (len - 1)) { //收最后1byte cfg |= STOP_FLAG | NACK; } buf[i] = bsp_hw_i2c_config(cfg | DATA_CNT_1B, dev_addr, reg_addr, 0); } bsp_i2c0_unlock(); } void i2c0_init(void) { CLKCON1 |= BIT(7); //x26m_clkdiv8 CLKGAT2 |= BIT(0); //en iic0 clk RSTCON0 |= BIT(3); //Release IIC0 GPIOEDIR |= BIT(2) | BIT(1); //SCL SDA GPIOEPU |= BIT(2) | BIT(1); GPIOEDE |= BIT(2) | BIT(1); GPIOEFEN |= BIT(2) | BIT(1); FUNCMCON2 = (0xf << 8); FUNCMCON2 = (5 << 8); IIC0CON0 = 1 << 0 | //IIC EN 0 << 1 | //IIC INT 0 << 2 | //IIC HOLD CNT [3:2] 20 << 4 | //IIC POSDIV [9:4] 1 << 10; //IIC WSCL_OPT delay_5ms(8); } #endif AT(.text.bsp.i2c) void bsp_i2c_init(void) { #if I2C_SW_EN I2C_SDA_SCL_OUT(); I2C_SDA_H(); delay_5ms(2); #endif #if I2C_HW_EN i2c0_init(); sys_irq_init(IRQ_I2C_VECTOR, 0, bsp_i2c_isr); #endif }