|
发表于 2016-9-28 10:34:19
|
显示全部楼层
贴上在使用中的I2C代码<从openpilot的i2c代码中提炼出来的>,采用中断(最高优先级)+库,目前没有发现什么问题,欢迎大家测试使用,呵呵。
int bsp_i2c_transfer(i2c_dev_s *i2cx, uint8_t addr, uint8_t reg,
uint8_t *data, uint8_t len, i2c_txn_direction rw)
{
int res;
if(!i2cx)
return -1;
sem_lock(i2cx->sem_busy);
active_i2cx = i2cx; //use for irq routine
if(data && len != 0) //valid data to send
{
i2c_txn.active_byte = &data[0];
i2c_txn.last_byte = &data[len - 1];
i2c_txn.bytes = len;
}
else
{
i2c_txn.last_byte = NULL;
i2c_txn.active_byte = i2c_txn.last_byte + 1;
i2c_txn.bytes = 0;
}
i2c_txn.slave_addr = (addr << 1);
i2c_txn.sub_addr = reg;
i2c_txn.rw = rw;
I2C_GenerateSTART(i2cx->dev, ENABLE);
I2C_ITConfig(i2cx->dev, I2C_IT_EVT | I2C_IT_ERR, ENABLE);
res = sem_wait(i2cx->sem_ready, TIMEOUT);
if(res < 0)
{
i2c_reset_bus(i2cx);
// dbg_log("BUS ERR.\r\n");
}
sem_unlock(i2cx->sem_busy);
return res;
}
static void i2c_ev_handler(void)
{
uint32_t event = I2C_GetLastEvent(active_i2cx->dev);
static uint8_t subaddr_send = 0;
#define EVENT_MASK 0x000700FF
event &= EVENT_MASK;
switch(event)
{
case (I2C_EVENT_MASTER_MODE_SELECT | 0x40):
(void)active_i2cx->dev->DR; //no break;
case I2C_EVENT_MASTER_MODE_SELECT: /* EV5 */
// I2C_AcknowledgeConfig(active_i2cx->dev, ENABLE);
if((i2c_txn.rw == I2C_TXN_READ) \
&& (subaddr_send || (i2c_txn.sub_addr == SUB_ADDR_NO_USE)))
I2C_Send7bitAddress(active_i2cx->dev, i2c_txn.slave_addr, I2C_Direction_Receiver);
else //direction is Tx, or we have not sent the sub and rep start
I2C_Send7bitAddress(active_i2cx->dev, i2c_txn.slave_addr, I2C_Direction_Transmitter);
break;
case I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED:/* EV6 */
I2C_ITConfig(active_i2cx->dev, I2C_IT_BUF, ENABLE); // allow us to have an EV8_1
break;
case I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED: /* EV6 */
if(i2c_txn.bytes == 1) // EV6_1
{
I2C_AcknowledgeConfig(active_i2cx->dev, DISABLE);
I2C_GenerateSTOP(active_i2cx->dev, ENABLE);
}
else if(i2c_txn.bytes >= 2)
{
I2C_AcknowledgeConfig(active_i2cx->dev, ENABLE);
}
I2C_ITConfig(active_i2cx->dev, I2C_IT_BUF, ENABLE);// allow us to have an EV7
break;
case I2C_EVENT_MASTER_BYTE_TRANSMITTING: /* EV8 or EV8_1 */
if(subaddr_send == 0 && i2c_txn.sub_addr != SUB_ADDR_NO_USE)
{
subaddr_send = 1;
active_i2cx->dev->DR = i2c_txn.sub_addr;
if(i2c_txn.rw == I2C_TXN_READ) // disable TXE to allow the buffer to flush
I2C_ITConfig(active_i2cx->dev, I2C_IT_BUF, DISABLE);
}
else if(i2c_txn.rw == I2C_TXN_WRITE)
{
if(i2c_txn.active_byte < i2c_txn.last_byte) // write more bytes
active_i2cx->dev->DR = *i2c_txn.active_byte++;
else if(i2c_txn.active_byte == i2c_txn.last_byte)
{ // the last byte
active_i2cx->dev->DR = *i2c_txn.active_byte++;
I2C_ITConfig(active_i2cx->dev, I2C_IT_BUF, DISABLE);
}
else // invalid data, wait for EV8_2
I2C_ITConfig(active_i2cx->dev, I2C_IT_BUF, DISABLE);
}
else //subaddress not used for read
I2C_ITConfig(active_i2cx->dev, I2C_IT_BUF, DISABLE);
break;
case I2C_EVENT_MASTER_BYTE_TRANSMITTED: /* EV8_2 */
if(i2c_txn.rw == I2C_TXN_READ)
I2C_GenerateSTART(active_i2cx->dev, ENABLE);
else
{
I2C_GenerateSTOP(active_i2cx->dev, ENABLE); // program the Stop
I2C_ITConfig(active_i2cx->dev, I2C_IT_EVT | I2C_IT_ERR, DISABLE);
subaddr_send = 0;
sem_post(active_i2cx->sem_ready);
}
break;
case I2C_EVENT_MASTER_BYTE_RECEIVED: /* EV7 */
switch(i2c_txn.last_byte - i2c_txn.active_byte + 1)
{
case 0:
(void)active_i2cx->dev->DR;
I2C_ITConfig(active_i2cx->dev, I2C_IT_EVT | I2C_IT_BUF |I2C_IT_ERR, DISABLE);
subaddr_send = 0;
sem_post(active_i2cx->sem_ready);
break;
case 1:
*i2c_txn.active_byte++ = active_i2cx->dev->DR;
I2C_ITConfig(active_i2cx->dev, I2C_IT_EVT | I2C_IT_BUF |I2C_IT_ERR, DISABLE);
subaddr_send = 0;
sem_post(active_i2cx->sem_ready);
break;
case 2:
I2C_AcknowledgeConfig(active_i2cx->dev, DISABLE);
I2C_GenerateSTOP(active_i2cx->dev, ENABLE);
*i2c_txn.active_byte++ = active_i2cx->dev->DR;
break;
default:
*i2c_txn.active_byte++ = active_i2cx->dev->DR;
break;
}
break;
case (I2C_EVENT_MASTER_BYTE_RECEIVED | 0x4): /* EV7 + BTF */
case 0: /* This triggers an FSM fault sometimes, but not having it stops things working */
case 0x40: /* RxNE only. MSL + BUSY have already been cleared by HW. */
case 0x44: /* RxNE + BTF. MSL + BUSY have already been cleared by HW. */
case 0x84: /* TxE + BTF. EV8_2 but TRA + MSL + BUSY have already been cleared by HW. */
break;
case 0x80:/* TxE only */
break;
case 0x30084: /* Occurs between byte tranmistted and master mode selected */
case 0x30000: /* Need to throw away this spurious event */
case 0x30403 & EVENT_MASK: /* Detected this after got a NACK, probably stop bit */
break;
default:
subaddr_send = 0;
i2c_reset_bus(active_i2cx);
break;
}
}
static void i2c_er_handler(void)
{
uint32_t event = I2C_GetLastEvent(active_i2cx->dev);
if (event & I2C_FLAG_AF)
{
I2C_ClearFlag(active_i2cx->dev, I2C_FLAG_AF);
I2C_ITConfig(active_i2cx->dev, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR, DISABLE);
I2C_AcknowledgeConfig(active_i2cx->dev, DISABLE);
I2C_GenerateSTOP(active_i2cx->dev, ENABLE);
}
else /* mostly bus errors here */
{
i2c_reset_bus(active_i2cx);/* Fail hard on any errors for now */
}
} |
|