Go Down

Topic: I2C + DMA (Read 13234 times) previous topic - next topic

EwingKang

EDIT2: Warning: this code does not correctly set the stop condition. It should be set prior to the last byte being transferred. For an N-byte transfer, we can transfer N-1 bytes by PDC, then interrupt, set the STOP flag and then send the last byte, also by PDC.
I've edited this code to always set the stop condition before activating the PDC, which works for 1-byte transfers. You can put it together or I might post my library when it's finished :)
/EDIT

I've got I2C working with PDC. It wasn't easy and the code is not pretty (yet) but it should get you started!

I'm writing an event-driven architecture where multiple drivers can communicate with one device each on the same I2C bus. There's some work left but when I'm done I should be able to run multiple I2C devices with nearly zero CPU overhead :)

Code: [Select]
#include <Arduino.h>
#define DeviceID                0x34
#define DeviceAddress           0x68
#define MPU6050_RA_WHO_AM_I     0x75
#define MPU6050_WHO_AM_I_BIT    6
#define MPU6050_WHO_AM_I_LENGTH 6
#define TWI_CLOCK               100000
uint8_t count = 0;
bool didWeRead;
enum ServiceState : uint8_t {
        FinishedReading,
        FinishedWriting,
        FinishedWaiting,
};

static inline void TWI_PDCWrite(uint8_t *data, uint16_t count) {
        WIRE_INTERFACE->TWI_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTDIS;
        WIRE_INTERFACE->TWI_TPR = (RwReg)data;
        WIRE_INTERFACE->TWI_TCR = count;
        WIRE_INTERFACE->TWI_TNPR = 0;
        WIRE_INTERFACE->TWI_TNCR = 0;
}
static inline void TWI_PDCRead(uint8_t *data, uint16_t count) {
        WIRE_INTERFACE->TWI_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTDIS;
        WIRE_INTERFACE->TWI_RPR = (RwReg)data;
        WIRE_INTERFACE->TWI_RCR = count;
        WIRE_INTERFACE->TWI_RNPR = 0;
        WIRE_INTERFACE->TWI_RNCR = 0;
}

static inline void TWI_MasterModeWrite(uint8_t deviceAddress) {
        WIRE_INTERFACE->TWI_MMR = TWI_MMR_IADRSZ_NONE | TWI_MMR_DADR(deviceAddress);
        WIRE_INTERFACE->TWI_CR = TWI_CR_MSEN;
}
static inline void TWI_MasterModeRead(uint8_t deviceAddress) {
        WIRE_INTERFACE->TWI_MMR = TWI_MMR_IADRSZ_NONE | TWI_MMR_DADR(deviceAddress) | TWI_MMR_MREAD;
        WIRE_INTERFACE->TWI_CR = TWI_CR_MSEN;
}

static inline void TWI_Write() {
        didWeRead = false;
        WIRE_INTERFACE->TWI_CR = TWI_CR_START | TWI_CR_STOP;
        WIRE_INTERFACE->TWI_IER = TWI_IER_ENDTX;
        WIRE_INTERFACE->TWI_PTCR = TWI_PTCR_TXTEN;
}
static inline void TWI_Read() {
        didWeRead = true;
        WIRE_INTERFACE->TWI_CR = TWI_CR_START | TWI_CR_STOP;
        WIRE_INTERFACE->TWI_IER = TWI_IER_ENDRX;
        WIRE_INTERFACE->TWI_PTCR = TWI_PTCR_RXTEN;
}

void write() {
        TWI_PDCWrite(&count, 1);
        TWI_MasterModeWrite(DeviceAddress);
        TWI_Write();
        count++;
}
uint8_t received[8];
void read() {
        TWI_PDCRead(received, 8);
        TWI_MasterModeRead(DeviceAddress);
        TWI_Read();
}
void InitializeTWI() {
        pmc_enable_periph_clk(WIRE_INTERFACE_ID);
        PIO_Configure(
                        g_APinDescription[PIN_WIRE_SDA].pPort,
                        g_APinDescription[PIN_WIRE_SDA].ulPinType,
                        g_APinDescription[PIN_WIRE_SDA].ulPin,
                        g_APinDescription[PIN_WIRE_SDA].ulPinConfiguration);
        PIO_Configure(
                        g_APinDescription[PIN_WIRE_SCL].pPort,
                        g_APinDescription[PIN_WIRE_SCL].ulPinType,
                        g_APinDescription[PIN_WIRE_SCL].ulPin,
                        g_APinDescription[PIN_WIRE_SCL].ulPinConfiguration);

        NVIC_DisableIRQ(TWI1_IRQn);
        NVIC_ClearPendingIRQ(TWI1_IRQn);
        NVIC_SetPriority(TWI1_IRQn, 0);
        NVIC_EnableIRQ(TWI1_IRQn);

        // Disable PDC channel
        WIRE_INTERFACE->TWI_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTDIS;

        TWI_ConfigureMaster(WIRE_INTERFACE, TWI_CLOCK, VARIANT_MCK);
}


void setup() {
        SerialUSB.begin(115200);
        Serial.begin(115200);
        InitializeTWI();
}

void loop() {
        write();
        delay(1000);
        //read();
        //delay(1000);
}

void TWI1_Handler() {
        int sr = WIRE_INTERFACE->TWI_SR;
        WIRE_INTERFACE->TWI_IDR = TWI_IDR_ENDTX | TWI_IDR_ENDRX;
        WIRE_INTERFACE->TWI_PTCR = TWI_PTCR_TXTDIS | TWI_PTCR_RXTDIS;
        WIRE_INTERFACE->TWI_CR = TWI_CR_STOP;
        if(didWeRead) {
                Serial.print("Read");
                for(int i = 0; i < 8; i++) {
                        Serial.print(" ");
                        Serial.print(received[i]);
                }
                Serial.println("");
        } else {
                long time = micros();
                while(!(WIRE_INTERFACE->TWI_SR & TWI_SR_TXRDY));
                time = micros() - time;
                Serial.print("Iterations: ");
                Serial.println(time);
                read();
        }
}


EDIT: I'm building with make, so perhaps there are some differences (like #include <Arduino.h>)
I couldn't get this code to work (with Arduino IDE) even messing it around for a while. The compile did pass, though.
Is it possible for you to provide a sample that can be used to make a basic communication with MPU 6050? I'll be very appreciated!

Go Up