mcu_ab568x/userboot240328/app/platform/bsp/bsp_i2c.c
2025-05-30 18:03:10 +08:00

272 lines
5.7 KiB
C

#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
}