Untitled
#include "ra6m3.h" // Configuration #define I2C_CLOCK_FREQUENCY 1000000 // 1 MHz (Fast Mode Plus) #define I2C_RETRY_COUNT 3 // Retry attempts for stuck conditions #define I2C_DMA_THRESHOLD 32 // Threshold for using DMA #define I2C_PERIPHERAL_BASE RIIC0 // Use RIIC0 peripheral #define SDA_PIN P1_2 // Replace with your SDA pin #define SCL_PIN P1_3 // Replace with your SCL pin // State variables volatile bool transfer_complete = false; volatile bool transfer_error = false; // Function prototypes void i2c_init(void); void i2c_set_clock(void); void i2c_bus_recovery(void); void i2c_isr_handler(void); void dma_init(void); // Optional: Initialize DMA for larger transfers int i2c_write(uint8_t addr, uint8_t *data, uint32_t length); int i2c_read(uint8_t addr, uint8_t *data, uint32_t length); // I2C Initialization void i2c_init(void) { // Enable peripheral clock for RIIC R_MSTP->MSTPCRB_b.MSTPB21 = 0; // Enable RIIC0 peripheral // Set SDA and SCL pins to proper mode PORT1->PDR_b.B2 = 1; // SDA PORT1->PDR_b.B3 = 1; // SCL PORT1->PMR_b.B2 = 1; // SDA PORT1->PMR_b.B3 = 1; // SCL // Reset and enable RIIC peripheral I2C_PERIPHERAL_BASE->CR1 = 0x00; // Disable RIIC I2C_PERIPHERAL_BASE->CR1 = 0x01; // Reset RIIC // Set I2C clock frequency i2c_set_clock(); // Enable I2C interrupts NVIC_EnableIRQ(RIIC0_TXI_IRQn); NVIC_EnableIRQ(RIIC0_RXI_IRQn); NVIC_EnableIRQ(RIIC0_TEI_IRQn); NVIC_EnableIRQ(RIIC0_NAKI_IRQn); // Enable RIIC I2C_PERIPHERAL_BASE->CR2 |= 0x01; } void i2c_set_clock(void) { uint32_t pclk = 120000000; // Peripheral clock frequency uint32_t ccr = pclk / (I2C_CLOCK_FREQUENCY * 8) - 1; // Set clock settings for Fast Mode Plus I2C_PERIPHERAL_BASE->CCR = ccr & 0xFF; I2C_PERIPHERAL_BASE->CCR2 = (ccr >> 8) & 0xFF; } // I2C Write int i2c_write(uint8_t addr, uint8_t *data, uint32_t length) { int retry = I2C_RETRY_COUNT; while (retry-- > 0) { transfer_complete = false; transfer_error = false; // Send start condition I2C_PERIPHERAL_BASE->CR2 |= 0x04; // Start condition while (!(I2C_PERIPHERAL_BASE->SR2 & 0x01)) ; // Wait for start condition // Send address I2C_PERIPHERAL_BASE->TDR = addr << 1; // Write bit while (!(I2C_PERIPHERAL_BASE->SR2 & 0x02)) ; // Wait for address transmission // Send data for (uint32_t i = 0; i < length; i++) { I2C_PERIPHERAL_BASE->TDR = data[i]; while (!(I2C_PERIPHERAL_BASE->SR2 & 0x02)) ; // Wait for byte transmission } // Send stop condition I2C_PERIPHERAL_BASE->CR2 |= 0x08; // Stop condition while (I2C_PERIPHERAL_BASE->CR2 & 0x08) ; // Wait for stop condition if (!transfer_error) { return 0; // Success } i2c_bus_recovery(); // Recover and retry } return -1; // Failed after retries } // I2C Read int i2c_read(uint8_t addr, uint8_t *data, uint32_t length) { int retry = I2C_RETRY_COUNT; while (retry-- > 0) { transfer_complete = false; transfer_error = false; // Send start condition I2C_PERIPHERAL_BASE->CR2 |= 0x04; // Start condition while (!(I2C_PERIPHERAL_BASE->SR2 & 0x01)) ; // Wait for start condition // Send address I2C_PERIPHERAL_BASE->TDR = (addr << 1) | 0x01; // Read bit while (!(I2C_PERIPHERAL_BASE->SR2 & 0x02)) ; // Wait for address transmission // Receive data for (uint32_t i = 0; i < length; i++) { while (!(I2C_PERIPHERAL_BASE->SR2 & 0x04)) ; // Wait for received byte data[i] = I2C_PERIPHERAL_BASE->RDR; } // Send stop condition I2C_PERIPHERAL_BASE->CR2 |= 0x08; // Stop condition while (I2C_PERIPHERAL_BASE->CR2 & 0x08) ; // Wait for stop condition if (!transfer_error) { return 0; // Success } i2c_bus_recovery(); // Recover and retry } return -1; // Failed after retries } // Bus Recovery void i2c_bus_recovery(void) { // Toggle SCL manually to free stuck bus PORT1->PDR_b.B3 = 1; // SCL as GPIO for (int i = 0; i < 9; i++) { PORT1->PODR_b.B3 = 1; // SCL High for (volatile int delay = 0; delay < 1000; delay++) ; PORT1->PODR_b.B3 = 0; // SCL Low for (volatile int delay = 0; delay < 1000; delay++) ; } PORT1->PDR_b.B3 = 0; // Return SCL to peripheral control } // ISR Handler (Simplified) void i2c_isr_handler(void) { if (I2C_PERIPHERAL_BASE->SR1 & 0x01) // Transfer complete { transfer_complete = true; } else if (I2C_PERIPHERAL_BASE->SR1 & 0x02) // Error { transfer_error = true; } } // Main int main(void) { uint8_t data[64]; i2c_init(); // Example write data[0] = 0xAA; if (i2c_write(0x50, data, 1) == 0) { // Write success } // Example read if (i2c_read(0x50, data, 10) == 0) { // Read success } while (1) { // Main loop } }
Leave a Comment