Untitled

 avatar
unknown
plain_text
25 days ago
5.4 kB
7
Indexable
#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