// ch32x035 and ch32v203 #include "ch32fun_i2c.h" #define I2C_TIMEOUT_MAX 100000 #define WAIT_FOR_FLAG(reg, flag) { \ uint32_t timeout = I2C_TIMEOUT_MAX; \ while (!((reg) & (flag))) { \ if (--timeout == 0) return -1; \ } \ } extern uint8_t * make_output_buffer(mrb_vm *vm, mrb_value v[], int argc, int start_idx, int *ret_bufsiz); #if !MRBC_USE_STRING extern mrbc_value mrbc_array_new_alloc(mrbc_vm *vm, const uint8_t *c_array, int size); #endif void i2c_init(){ RCC->APB1PCENR |= RCC_APB1Periph_I2C1; #if defined( CH32X03x ) AFIO->PCFR1 &= ~AFIO_PCFR1_SWJ_CFG; AFIO->PCFR1 |= AFIO_PCFR1_SWJ_CFG_DISABLE; GPIOC->CFGXR &= ~(0xF << 8 | 0xF << 12); //PC18 DIO, PC19 DCK GPIOC->CFGXR |= GPIO_CFGLR_OUT_50Mhz_AF_PP << 8 | GPIO_CFGLR_OUT_50Mhz_AF_PP << 12; AFIO->PCFR1 &= ~AFIO_PCFR1_I2C1_REMAP; AFIO->PCFR1 |= AFIO_PCFR1_I2C1_REMAP_1 | AFIO_PCFR1_I2C1_REMAP_0; //011 #elif defined( CH32V20x ) funPinMode(26,GPIO_CFGLR_OUT_50Mhz_AF_PP); //PB10 funPinMode(27,GPIO_CFGLR_OUT_50Mhz_AF_PP); //PB11 #endif I2C1->CTLR1 &= ~I2C_CTLR1_PE; I2C1->CTLR2 = (FUNCONF_SYSTEM_CORE_CLOCK / 1000000); I2C1->CKCFGR = FUNCONF_SYSTEM_CORE_CLOCK / (100000 << 1); //100kHz I2C1->CTLR1 |= I2C_CTLR1_PE; I2C1->CTLR1 |= I2C_CTLR1_ACK; } int i2c_start(uint8_t adrs, uint8_t rw){ // rw=1 if read uint32_t timeout = I2C_TIMEOUT_MAX; while (I2C1->STAR2 & I2C_STAR2_BUSY) { if (--timeout == 0) return -1; } I2C1->CTLR1 |= I2C_CTLR1_START; WAIT_FOR_FLAG(I2C1->STAR1, I2C_STAR1_SB); I2C1->DATAR = (adrs << 1) | rw; WAIT_FOR_FLAG(I2C1->STAR1, I2C_STAR1_ADDR); (void)I2C1->STAR1; (void)I2C1->STAR2; return 0; } int i2c_write(const uint8_t *buf, uint16_t len){ for (uint16_t i = 0; i < len; i++) { WAIT_FOR_FLAG(I2C1->STAR1, I2C_STAR1_TXE); I2C1->DATAR = buf[i]; } WAIT_FOR_FLAG(I2C1->STAR1, I2C_STAR1_BTF); return 0; } int i2c_read(uint8_t *buf, uint16_t len){ I2C1->CTLR1 |= I2C_CTLR1_ACK; for (uint16_t i = 0; i < len; i++) { if(i==len-1) I2C1->CTLR1 &= ~I2C_CTLR1_ACK; WAIT_FOR_FLAG(I2C1->STAR1, I2C_STAR1_RXNE); buf[i] = I2C1->DATAR; } I2C1->CTLR1 |= I2C_CTLR1_STOP; return 0; } void c_i2c_new(mrb_vm *vm, mrb_value *v, int argc){ i2c_init(); } void c_i2c_write(mrb_vm *vm, mrb_value *v, int argc){ uint8_t *buf = 0; int bufsiz = 0; if( argc>0 ){ uint8_t adrs = GET_INT_ARG(1); i2c_start(adrs,0); if(argc>1){ buf = make_output_buffer( vm, v, argc, 2, &bufsiz ); i2c_write(buf, bufsiz); mrbc_free( vm, buf ); } I2C1->CTLR1 |= I2C_CTLR1_STOP; } SET_RETURN( mrbc_integer_value(bufsiz) ); } void c_i2c_read(mrb_vm *vm, mrb_value *v, int argc){ uint8_t *buf = 0; int bufsiz = 0; mrbc_value ret = mrbc_nil_value(); if( argc>1 ){ int adrs = GET_INT_ARG(1); int size = GET_INT_ARG(2); if( argc > 2 ) { i2c_start(adrs,0); buf = make_output_buffer( vm, v, argc, 3, &bufsiz ); i2c_write(buf, bufsiz); mrbc_free( vm, buf ); } buf = mrbc_alloc(vm, size); i2c_start(adrs,1); i2c_read(buf,size); #if MRBC_USE_STRING ret = mrbc_string_new_alloc(vm, buf, size); #else ret = mrbc_array_new_alloc( vm, buf, size); mrbc_free( vm, buf ); #endif } SET_RETURN(ret); } void mrbc_init_class_i2c(void){ mrb_class *i2c = mrbc_define_class(0, "I2C", mrbc_class_object); mrbc_define_method(0, i2c, "new", c_i2c_new); mrbc_define_method(0, i2c, "read", c_i2c_read); mrbc_define_method(0, i2c, "write", c_i2c_write); }