Сб ноя 19, 2022 11:36:08
#include "em_device.h"
#include "em_cmu.h"
#include "em_gpio.h"
#include "i2c_drv.h"
#include "resources.h"
#define I2C_DEV_NUM 1
#define I2C_DEV I2C1
#define I2C_IRQn I2C1_IRQn
#define I2C_IRQHandler I2C1_IRQHandler
#define CMU_CLOCK cmuClock_I2C1
#define SDA_PORT gpioPortC
#define SCL_PORT gpioPortC
#define SDA_PIN (1)
#define SCL_PIN (2)
typedef enum {
send_reg_hi,
send_reg_lo,
send_data,
rcv_reg_hi,
rcv_reg_lo,
rcv_restart,
rcv_data,
rcv_stop,
i2c_stop,
i2c_idle,
} i2c_state_t;
volatile i2c_state_t i2c_state = i2c_idle;
volatile unsigned int data_count, i2c_register[2], i2c_addr;
unsigned char * volatile data_ptr;
volatile t_i2c_status i2c_error_code;
#define DEBUG_I2C
#ifdef DEBUG_I2C
volatile uint8_t debug_str[256], *debug_str_ptr = 0;
uint8_t hex_str[] = "0123456789ABCDEF";
#endif
void i2c_master_init(void) {
// включаем внутренние подтяжки на всякий случай.
// И тогда в некоторых случаях можно обойтись и без внешних резисторов.
CMU_ClockEnable(CMU_CLOCK, 1);
GPIO_PinModeSet(SDA_PORT, SDA_PIN, gpioModeWiredAndPullUp, 1);
GPIO_PinModeSet(SCL_PORT, SCL_PIN, gpioModeWiredAndPullUp, 1);
// Конфигурируем
I2C_DEV->CTRL = I2C_CTRL_GIBITO | I2C_CTRL_BITO_I2C160PCC; // | I2C_CTRL_TXBIL_HALF_FULL; // | I2C_CTRL_AUTOSN;
{
unsigned int refFreq, clkdiv;
const unsigned int baudrate = 400000;
refFreq = CMU_ClockFreqGet(cmuClock_PCLK);
clkdiv = refFreq / baudrate;
clkdiv = (clkdiv - 8 +4 ) / 8 ;
I2C_DEV->CLKDIV = clkdiv-1;
}
I2C_DEV->IEN = I2C_IEN_ARBLOST | I2C_IEN_NACK | I2C_IEN_RXDATAV |
I2C_IEN_START | I2C_IEN_MSTOP | I2C_IEN_ACK;
// подключаем выводы
GPIO->I2CROUTE[I2C_DEV_NUM].SCLROUTE = SCL_PORT | (SCL_PIN << _GPIO_I2C_SCLROUTE_PIN_SHIFT);
GPIO->I2CROUTE[I2C_DEV_NUM].SDAROUTE = SDA_PORT | (SDA_PIN << _GPIO_I2C_SDAROUTE_PIN_SHIFT);
GPIO->I2CROUTE[I2C_DEV_NUM].ROUTEEN = GPIO_I2C_ROUTEEN_SCLPEN | GPIO_I2C_ROUTEEN_SDAPEN;
I2C_DEV->EN = I2C_EN_EN;
I2C_DEV->CMD = I2C_CMD_ABORT | I2C_CMD_CLEARTX | I2C_CMD_CLEARPC;
NVIC_SetPriority(I2C_IRQn, I2C_IRQ_PRI);
NVIC_EnableIRQ(I2C_IRQn);
}
void I2C_IRQHandler(void) {
if ((I2C_DEV->IEN & I2C_IEN_ARBLOST) && (I2C_DEV->IF & I2C_IF_ARBLOST)) {// Arbitration lost; Interrupt Flag: UCALIFG; Interrupt
#ifdef DEBUG_I2C
if (debug_str_ptr) *debug_str_ptr++ = 'A';
#endif
i2c_error_code = I2C_ERROR;
i2c_state = i2c_idle;
I2C_DEV->IF_CLR = I2C_IF_ARBLOST;
}
if ((I2C_DEV->IEN & I2C_IEN_START) && (I2C_DEV->IF & I2C_IF_START)) { // Start condition received; Interrupt Flag: UCSTTIFG
#ifdef DEBUG_I2C
if (debug_str_ptr) *debug_str_ptr++ = 'S';
if (debug_str_ptr) *debug_str_ptr++ = hex_str[(i2c_addr & 0xF0) >> 4];
if (debug_str_ptr) *debug_str_ptr++ = hex_str[(i2c_addr & 0x0F)];
#endif
I2C_DEV->TXDATA = i2c_addr;
I2C_DEV->IF_CLR = I2C_IF_START;
if (i2c_state != rcv_data) {
BUS_RegMaskedSet(&I2C_DEV->IEN, I2C_IEN_TXBL);
}
}
if ((I2C_DEV->IEN & I2C_IEN_RXDATAV) && (I2C_DEV->IF & I2C_IF_RXDATAV)) { // Data received; Interrupt Flag: UCRXIFG0
#ifdef DEBUG_I2C
if (debug_str_ptr) *debug_str_ptr++ = 'R';
#endif
*data_ptr++ = I2C_DEV->RXDATA;
I2C_DEV->IF_CLR= I2C_IF_RXDATAV;
if (--data_count) {
I2C_DEV->CMD = I2C_CMD_ACK;
} else {
i2c_state = rcv_stop;
I2C_DEV->CMD = I2C_CMD_NACK | I2C_CMD_STOP;
}
}
if ((I2C_DEV->IEN & I2C_IEN_TXBL) && (I2C_DEV->IF & I2C_IF_TXBL)) { // Transmit buffer empty; Interrupt Flag: UCTXIFG0
#ifdef DEBUG_I2C
if (debug_str_ptr) *debug_str_ptr++ = 'T';
#endif
I2C_DEV->IF_CLR = I2C_IF_TXBL;
switch (i2c_state) {
case rcv_reg_hi:
#ifdef DEBUG_I2C
if (debug_str_ptr) *debug_str_ptr++ = 'h';
#endif
i2c_state = rcv_reg_lo;
I2C_DEV->TXDATA = i2c_register[1];
break;
case rcv_reg_lo:
#ifdef DEBUG_I2C
if (debug_str_ptr) *debug_str_ptr++ = 'l';
#endif
i2c_state = rcv_restart;
BUS_RegMaskedClear(&I2C_DEV->IEN, I2C_IEN_TXBL);
I2C_DEV->TXDATA = i2c_register[0];
break;
case send_reg_hi:
#ifdef DEBUG_I2C
if (debug_str_ptr) *debug_str_ptr++ = 'n';
#endif
i2c_state = send_reg_lo;
I2C_DEV->TXDATA = i2c_register[1];
break;
case send_reg_lo:
#ifdef DEBUG_I2C
if (debug_str_ptr) *debug_str_ptr++ = 'n';
#endif
i2c_state = send_data;
I2C_DEV->TXDATA = i2c_register[0];
break;
case send_data:
#ifdef DEBUG_I2C
if (debug_str_ptr) *debug_str_ptr++ = 'd';
#endif
if (data_count) {
I2C_DEV->TXDATA = *data_ptr++;
--data_count;
} else {
i2c_state = i2c_stop;
BUS_RegMaskedClear(&I2C_DEV->IEN, I2C_IEN_TXBL);
}
break;
default:
break;
}
}
if ((I2C_DEV->IEN & I2C_IEN_MSTOP) && (I2C_DEV->IF & I2C_IF_MSTOP)) { // Stop condition received; Interrupt Flag: UCSTPIFG
#ifdef DEBUG_I2C
if (debug_str_ptr) *debug_str_ptr++ = '\0';
debug_str_ptr = 0;
#endif
i2c_state = i2c_idle;
I2C_DEV->CMD = I2C_CMD_CLEARTX | I2C_CMD_CLEARPC;
I2C_DEV->IF_CLR = I2C_IF_MSTOP;
BUS_RegMaskedClear(&I2C_DEV->IEN, I2C_IEN_TXBL);
}
if ((I2C_DEV->IEN & I2C_IEN_ACK) && (I2C_DEV->IF & I2C_IF_ACK)) { // Not acknowledgment; Interrupt Flag: UCNACKIFG
#ifdef DEBUG_I2C
if (debug_str_ptr) *debug_str_ptr++ = 'K';
#endif
I2C_DEV->IF_CLR = I2C_IF_ACK;
if (i2c_state == i2c_stop) {
I2C_DEV->CMD = I2C_CMD_STOP;
}
if (i2c_state == rcv_restart) {
i2c_state = rcv_data;
i2c_addr |= 0x01;
I2C_DEV->CMD = I2C_CMD_START;
}
}
if ((I2C_DEV->IEN & I2C_IEN_NACK) && (I2C_DEV->IF & I2C_IF_NACK)) { // Not acknowledgment; Interrupt Flag: UCNACKIFG
#ifdef DEBUG_I2C
if (debug_str_ptr) *debug_str_ptr++ = 'N';
#endif
i2c_error_code = I2C_NAK_ADDR;
i2c_state = i2c_stop;
I2C_DEV->IF_CLR = I2C_IF_NACK;
BUS_RegMaskedClear(&I2C_DEV->IEN, I2C_IEN_TXBL);
I2C_DEV->CMD = I2C_CMD_STOP;
}
}
t_i2c_status i2c_wr(uint8_t address, unsigned char * data, unsigned int length) {
if (i2c_state != i2c_idle) return I2C_BUSY;
data_ptr = data;
data_count = length;
// i2c_register = reg_addr;
i2c_state = send_data;
i2c_error_code = I2C_SUCCESS;
i2c_addr = address & ~0x01;
I2C_DEV->CMD = I2C_CMD_START;
while (i2c_state != i2c_idle) continue;
return i2c_error_code;
}
t_i2c_status i2c_rd(uint8_t address, unsigned char * data, unsigned int length) {
if (i2c_state != i2c_idle) return I2C_BUSY;
data_ptr = data;
data_count = length;
i2c_state = rcv_data;
i2c_addr = address |= 0x01;
i2c_error_code = I2C_SUCCESS;
I2C_DEV->CMD = I2C_CMD_START;
while (i2c_state != i2c_idle) continue;
return i2c_error_code;
}
t_i2c_status i2c_wr_reg(uint8_t address, uint8_t reg_addr, unsigned char * data, unsigned int length) {
if (i2c_state != i2c_idle) return I2C_BUSY;
data_ptr = data;
data_count = length;
i2c_register[0] = reg_addr;
i2c_state = send_reg_lo;
i2c_error_code = I2C_SUCCESS;
i2c_addr = address & ~0x01;
I2C_DEV->CMD = I2C_CMD_START;
while (i2c_state != i2c_idle) continue;
return i2c_error_code;
}
t_i2c_status i2c_rd_reg(uint8_t address, uint8_t reg_addr, unsigned char * data, unsigned int length) {
if (i2c_state != i2c_idle) return I2C_BUSY;
data_ptr = data;
data_count = length;
i2c_register[0] = reg_addr;
i2c_state = rcv_reg_lo;
i2c_addr = address & ~0x01;
i2c_error_code = I2C_SUCCESS;
I2C_DEV->CMD = I2C_CMD_START;
while (i2c_state != i2c_idle) continue;
return i2c_error_code;
}
t_i2c_status i2c_wr_reg16(uint8_t address, uint16_t reg_addr, unsigned char * data, unsigned int length) {
if (i2c_state != i2c_idle) return I2C_BUSY;
data_ptr = data;
data_count = length;
i2c_register[0] = (reg_addr & 0x00FF);
i2c_register[1] = (reg_addr & 0xff00) >> 8;
i2c_state = send_reg_lo;
i2c_error_code = I2C_SUCCESS;
i2c_addr = address & ~0x01;
I2C_DEV->CMD = I2C_CMD_START;
while (i2c_state != i2c_idle) continue;
return i2c_error_code;
}
t_i2c_status i2c_rd_reg16(uint8_t address, uint16_t reg_addr, unsigned char * data, unsigned int length) {
if (i2c_state != i2c_idle) return I2C_BUSY;
#ifdef DEBUG_I2C
debug_str_ptr = debug_str;
#endif
data_ptr = data;
data_count = length;
i2c_register[0] = (reg_addr & 0x00FF);
i2c_register[1] = (reg_addr & 0xFF00) >> 8;
i2c_state = rcv_reg_hi;
i2c_error_code = I2C_SUCCESS;
i2c_addr = address & ~0x01;
I2C_DEV->CMD = I2C_CMD_START;
while (i2c_state != i2c_idle) continue;
return i2c_error_code;
}
Сб ноя 19, 2022 12:10:27
Логического анализатора у меня нет, но я догадываюсь