#include "board.h" //static struct rt_event event_i2c1; //static uint8_t SlvAddrRWE; //static uint8_t *PtrBuf; //static int16_t BufLen; //static uint32_t PinSCL; //static uint32_t PinSDA; #define I2C1_CR_CFG ( \ (1<<6) | /* ens, I2C module 0:off; 1:on; */ \ (1<<0) /* hlm, 0:advance filter(TM must>9); 1:simple filter; */ \ ) #define I2C1_CR_START (1u<<5) #define I2C1_CR_STOP (1u<<4) #define I2C1_CR_SI (1u<<3) #define I2C1_CR_HOLD (1u<<3) #define I2C1_CR_NEXT (0u<<3) #define I2C1_CR_ACK (1u<<2) #define I2C1_CR_NACK (0u<<2) typedef enum i2c_stat_code{ I2C_TX_START = 0x08u, I2C_TX_RESTART = 0x10u, I2C_TX_WADDR_ACK = 0x18u, I2C_TX_WADDR_NACK = 0x20u, I2C_TX_WDATA_ACK = 0x28u, I2C_TX_WDATA_NACK = 0x30u, I2C_TX_CLOCK_FAIL = 0x38u, I2C_TX_RADDR_ACK = 0x40u, I2C_TX_RADDR_NACK = 0x48u, I2C_RX_RDATA_ACK = 0x50u, I2C_RX_RDATA_NACK = 0x58u, I2C_RX_WADDR_ACK = 0x60u, I2C_RX_WADDR_ACK_M2S = 0x68u, I2C_RX_WDATA_ACK = 0x80u, I2C_RX_WDATA_NACK = 0x88u, I2C_RX_WEND = 0xA0u, I2C_RX_RADDR_ACK = 0xA8u, I2C_RX_RADDR_ACK_M2S = 0xB0u, I2C_TX_RDATA_ACK = 0xB8u, I2C_TX_RDATA_NACK = 0xC0u, } i2c_stat_code_t; // PD10: 1:power on; 0:power off; // PA15: write protect for EEPROM, 1: write forbid; 0:allow write; // PF07: I2C1_SDA // PF06: I2C1_SCL void eeprom_init(void) // for EEPROM(M24M01 128KByts) chip { // GpioSetPins(GpioPortD, GpioBitMsk10); // power on GpioClrPins(GpioPortD, GpioBitMsk10); // power off GpioInit(PD10_AF0, GPIO_DIG_OUT_WEAK_PUSH_NONEUP_NONEDOWN); // keep I2C1_WP same level as PIN_VCC_I2C for saving power // GpioSetPins(GpioPortA, GpioBitMsk15); // write protect on GpioClrPins(GpioPortA, GpioBitMsk15); // write protect off GpioInit(PA15_AF0, GPIO_DIG_OUT_WEAK_PUSH_NONEUP_NONEDOWN); PeriClk_MutEnable(PeriClk_I2c1); MutResetPeri(ResetI2c1); // not asynchronous reset, must be effective after enable clock // Fscl = Fpclk/8/(TM+1) #if defined(SYSCLK_4M_MODE) M0P_I2C1->TM = 0x1; // Fscl = 250KHz #elif defined(SYSCLK_8M_MODE) M0P_I2C1->TM = 0x1; // Fscl = 500KHz #elif defined(SYSCLK_16M_MODE) M0P_I2C1->TM = 0x3; // Fscl = 500KHz #endif M0P_I2C1->TMRUN = 0x1; // 0:Baud rate off; 1:Baud rate on; M0P_I2C1->CR = I2C1_CR_CFG | I2C1_CR_HOLD; PeriClk_MutDisable(PeriClk_I2c1); // EEPROM GpioInit(PF06_I2C1_SCL, GPIO_DIG_OUT_WEAK_OPEN_NONEUP_NONEDOWN); // set pin to output open GpioInit(PF07_I2C1_SDA, GPIO_DIG_OUT_WEAK_OPEN_NONEUP_NONEDOWN); // set pin to output open // // enable interrupt at NVIC side // IRQMutEnable(I2C1_IRQn, IRQnPriority3); } void i2c1_rescue(void) { int16_t i; GpioSetPins(GpioPortF, GpioBitMsk6); // I2C1_SCL GpioSetPins(GpioPortF, GpioBitMsk7); // I2C1_SDA GpioInit(PF06_AF0, GPIO_DIG_OUT_WEAK_OPEN_NONEUP_NONEDOWN); // set pin to output open GpioInit(PF07_AF0, GPIO_DIG_OUT_WEAK_OPEN_NONEUP_NONEDOWN); // set pin to output open i = 10; while(i--){ GpioClrPins(GpioPortF, GpioBitMsk6); // I2C1_SCL GpioSetPins(GpioPortF, GpioBitMsk6); // I2C1_SCL } GpioInit(PF06_I2C1_SCL, GPIO_DIG_OUT_WEAK_OPEN_NONEUP_NONEDOWN); // set pin to output open GpioInit(PF07_I2C1_SDA, GPIO_DIG_OUT_WEAK_OPEN_NONEUP_NONEDOWN); // set pin to output open } // Len is for data only, address byte is not included uint8_t I2C1_RdWrPacket(uint8_t AddrRWE, uint8_t *Buf, uint16_t Len) { uint8_t i2c_next; uint8_t i2c_error; PeriClk_MutEnable(PeriClk_I2c1); M0P_I2C1->CR = I2C1_CR_CFG | I2C1_CR_START | I2C1_CR_NEXT; i2c_next = 0x1u; while(i2c_next){ while((~M0P_I2C1->CR) & I2C1_CR_SI){ // wait until SI=1 } switch(M0P_I2C1->STAT){ case(I2C_TX_START): case(I2C_TX_RESTART): M0P_I2C1->DATA = AddrRWE; M0P_I2C1->CR = I2C1_CR_CFG | I2C1_CR_NEXT; break; case(I2C_TX_WADDR_ACK): case(I2C_TX_WDATA_ACK): if (Len<=0){ M0P_I2C1->CR = I2C1_CR_CFG | I2C1_CR_STOP | I2C1_CR_NEXT; i2c_error = 0x0u; i2c_next = 0x0u; } else { Len--; M0P_I2C1->DATA = *(Buf++); M0P_I2C1->CR = I2C1_CR_CFG | I2C1_CR_NEXT; } break; case(I2C_RX_RDATA_ACK): case(I2C_RX_RDATA_NACK): *(Buf++) = M0P_I2C1->DATA; case(I2C_TX_RADDR_ACK): if (Len<=0){ M0P_I2C1->CR = I2C1_CR_CFG | I2C1_CR_STOP | I2C1_CR_NEXT; i2c_error = 0x0u; i2c_next = 0x0u; } else { if (Len==1){ M0P_I2C1->CR = I2C1_CR_CFG | I2C1_CR_NACK | I2C1_CR_NEXT; } else { M0P_I2C1->CR = I2C1_CR_CFG | I2C1_CR_ACK | I2C1_CR_NEXT; } Len--; } break; default: M0P_I2C1->CR = I2C1_CR_CFG | I2C1_CR_STOP | I2C1_CR_NEXT; i2c_error = 0x1u; i2c_next = 0x0u; } } PeriClk_MutDisable(PeriClk_I2c1); if (i2c_error){ return(0x1u); // fail } else { return(0x0u); // ok } } // NOTE: Page size is 256Bytes, so any write must not cross page boundary // size of Buf >= DLen+3 (Must) // Buf[0] is address A16 // Buf[1] is address A15-A8 // Buf[2] is address A7-A0 // Buf[3]~Buf[DLen+2] is WR data // DLen>=1, at least 1 WR data(be sure (A[7:0] + DLen) <=256) uint8_t EEPROM_WrPacket(uint8_t *Buf, uint16_t DLen) { uint8_t ret; uint8_t AddrRWE; GpioSetPins(GpioPortA, GpioBitMsk15); // write protect on GpioSetPins(GpioPortD, GpioBitMsk10); // power on AddrRWE = ((Buf[0]&0x01u)<<1) | 0xA0u; GpioClrPins(GpioPortA, GpioBitMsk15); // write protect off ret = I2C1_RdWrPacket(AddrRWE, Buf+1, DLen+2); GpioSetPins(GpioPortA, GpioBitMsk15); // write protect on //us_delay(5000); // tW = 5ms rt_thread_mdelay(5); // keep I2C1_WP same level as PIN_VCC_I2C for saving power GpioClrPins(GpioPortD, GpioBitMsk10); // power off GpioClrPins(GpioPortA, GpioBitMsk15); // write protect off return(ret); } // size of Buf >= DLen+3 (Must) // Buf[0] is address A16 // Buf[1] is address A15-A8 // Buf[2] is address A7-A0 // Buf[3]~Buf[DLen+2] is RD data // DLen>=1, at least 1 WR data uint8_t EEPROM_RdPacket(uint8_t *Buf, uint16_t DLen) { uint8_t ret; uint8_t AddrRWE; GpioSetPins(GpioPortA, GpioBitMsk15); // write protect on GpioSetPins(GpioPortD, GpioBitMsk10); // power on AddrRWE = ((Buf[0]&0x01u)<<1) | 0xA0u; ret = I2C1_RdWrPacket(AddrRWE, Buf+1, 2); if (ret){ return(ret); } AddrRWE |= 0x01u; ret = I2C1_RdWrPacket(AddrRWE, Buf+3, DLen); // keep I2C1_WP same level as PIN_VCC_I2C for saving power GpioClrPins(GpioPortD, GpioBitMsk10); // power off GpioClrPins(GpioPortA, GpioBitMsk15); // write protect off return(ret); }