KL25 I2C DMA

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

KL25 I2C DMA

1,372 Views
mqxman
Contributor I

Hello!

I trying develope data transfer (acceleration data, gyroscope data, tempertaure data) FRDM-KL25 <<------->> MPU6050 with I2C and DMA, Without DMA reading is going fine but with DMA is it still without success.

This is the code for read data from MPU6050 throug I2C without DMA this is going fine:

void read_MPU6050()

{

    I2CReadMultiRegisters(MPU6050_ADDRESS, MPU6050_RA_ACCEL_XOUT_H, &MPU_6050_buffer[0], 14);

    convert_data();   

}

void I2CReadMultiRegisters(char SlaveID, char RegisterAddress, char * r, char n)

{

  char i;

  uint32_t t[3];

  IIC_StartTransmission(SlaveID,MWSR);

  i2c_Wait();

  i2c_write_byte(RegisterAddress);

  i2c_Wait();

  i2c_RepeatedStart();

  i2c_write_byte((SlaveID << 1) | 0x01);

  i2c_Wait();

  i2c_EnterRxMode();

  i2c_EnableAck();

  i = I2C1_D ; // Dummy read

  i2c_Wait();

  for(i=0;i<n-2;i++)

  {

    *r = I2C1_D;

    r++;

    i2c_Wait();

  }

  i2c_DisableAck();

  *r = I2C1_D;

  r++;

  i2c_Wait();

  i2c_Stop();

  *r = I2C1_D;

  Pause();

}

Reading with DMA is this:

void DMAread_MPU6050(){

   

    DMA_I2CReadMultiRegisters(MPU6050_ADDRESS,MPU6050_RA_ACCEL_XOUT_H,&MPU_6050_buffer[0],14);

    convert_data();   

}

void DMA_I2CReadMultiRegisters(char SlaveID, char RegisterAddress, char * r, char n)

{

  char i;

  IIC_StartTransmission(SlaveID,MWSR);

  i2c_Wait();

  i2c_write_byte(RegisterAddress);

  i2c_Wait();

  i2c_RepeatedStart();

  i2c_write_byte((SlaveID << 1) | 0x01);

  i2c_Wait();

  i2c_EnterRxMode();

  i2c_EnableAck();

  i = I2C1_D ; // Dummy read

  i2c_Wait();

 

  DMA_starttransfer(DMA_BASE_PTR,0, 14);

}

void DMA_starttransfer(DMA_MemMapPtr DMA_Channel, uint8_t index, uint32_t num_bytes)

{

    DMA_DSR_REG(DMA_Channel, index) = num_bytes;

    DMA_DAR_REG(DMA_Channel, index) = (uint32_t)(&MPU_6050_buffer[0]);

    DMA_DCR_REG(DMA_Channel, index) = DMA_DCR_ERQ_MASK|DMA_DCR_EINT_MASK;

    I2C1_C1 |= I2C_C1_DMAEN_MASK;

}

This is the initialization code for DMA and I2C:

void Init_I2C(void)

{

  SIM_SCGC5 |= SIM_SCGC5_PORTC_MASK | SIM_SCGC5_PORTE_MASK | SIM_SCGC5_PORTB_MASK;

  SIM_SCGC4 |= SIM_SCGC4_I2C1_MASK;

  PORTC_PCR10 = PORT_PCR_MUX(2);        //I2C SCL

  PORTC_PCR11 = PORT_PCR_MUX(2);        //I2C SDA

  I2C1_F  = 0x00;

  I2C1_C1 = I2C_C1_IICEN_MASK;

}

void DMA_RX_Init(DMA_MemMapPtr DMA_Channel, uint8_t dma_source, int index,

        uint32_t source_addr, uint32_t dest_addr, uint32_t num_bytes,uint32_t bytes_per_xfer)

{

    /* num_bytes is total bytes */

    /* setup depends on how many bytes per transfer */

    SIM_SCGC6 |= SIM_SCGC6_DMAMUX_MASK;

    SIM_SCGC7 |= SIM_SCGC7_DMA_MASK;

    uint32_t ssize_dsize_attr;

    /* setup ssize and dsize parameter for TCD ATTR register based on transfer size assigned above */

    /* 0:32bit; 1:8-bit, 2:16-bit  */

    switch (bytes_per_xfer) {

    case 8:

    default:

        ssize_dsize_attr = 1;

        break; /* 8-bit */

    case 16:

        ssize_dsize_attr = 2;

        break; /* 16-bit */

    case 32:

        ssize_dsize_attr = 0;

        break; /* 32-bit */

    }

    DMA_SAR_REG(DMA_Channel, index)= source_addr;                                          // Source address

    DMA_DCR_REG(DMA_Channel, index)|= 0x0000;                                             // Source address increments 0 bytes (uint32)

    DMA_DAR_REG(DMA_Channel, index)|= dest_addr;                                           // Destination address

    DMA_DCR_REG(DMA_Channel, index)|= ssize_dsize_attr << DMA_DCR_DINC_SHIFT;                 // Destination offset increments

    DMA_DCR_REG(DMA_Channel, index)|= DMA_DCR_ERQ_MASK|DMA_DCR_EINT_MASK|DMA_DCR_D_REQ_MASK;//|DMA_DCR_CS_MASK;

    I2C1_C1 |= I2C_C1_DMAEN_MASK;//|I2C_C1_IICIE_MASK;

    DMA_DSR_BCR_REG(DMA_Channel, index)= num_bytes;                                            //Stop the transfer when all bytes is transfered

    DMA_DCR_REG(DMA_Channel, index)|= ((ssize_dsize_attr<<DMA_DCR_DSIZE_SHIFT)|(ssize_dsize_attr<<DMA_DCR_SSIZE_SHIFT)); // Source a destination size 0:32bit; 1:8-bit, 2:16-bit

    DMAMUX_CHCFG_REG(DMAMUX0_BASE_PTR,index)= (DMAMUX_CHCFG_ENBL_MASK | DMAMUX_CHCFG_SOURCE(dma_source)); // DMA source DMA Mux to tie source to DMA channel

}

And finally the main functon with DMA interrupt function:

int main(void)

{

    InitClock();

    InitSysTick();

    Init_I2C();

    DMA_RX_Init(DMA_BASE_PTR, I2C1_SOURCE, CHANNEL_0,

            (uint32_t) (&(I2C1_D )),(uint32_t)(&(MPU_6050_buffer[0])), 12,8 );   

    init_MPU6050();

    enable_irq(INT_DMA0 - 16);

       

    for(;;) {   

        read_MPU6050();

        //DMAread_MPU6050();

        counter++;

           Delay_mS(1000);

    }

        return 0;

}

void DMA_interrupt()

{

    i2c_DisableAck();

    i2c_Wait();

    i2c_Stop();

    interrupt++;

    DMA_DSR_BCR0 |= DMA_DSR_BCR_DONE_MASK;

    I2C1_C1 &= ~I2C_C1_DMAEN_MASK;

}

Iam working on this over the weekend but still not going. Can anyone help me and modify this code? I attach the whole of project. Thank You!

Labels (1)
0 Kudos
Reply
2 Replies

845 Views
mqxman
Contributor I

+datasheet, registry map for MPU6050

0 Kudos
Reply

844 Views
Jorge_Gonzalez
NXP Employee
NXP Employee

Hello Norbert Gal:

I am not familiar with that MPU6050 module and I don't have one to test, but by looking at your code these are some things I noticed:

- There is a line of DMA initialization code that does not make sense:

DMA_DCR_REG(DMA_Channel, index)|= ssize_dsize_attr << DMA_DCR_DINC_SHIFT;      // Destination offset increments

I guess this should be:

DMA_DCR_REG(DMA_Channel, index) |= 1 << DMA_DCR_DINC_SHIFT;      // Destination offset increments

- Also, the DMA requests should be enabled before the dummy read in Receive mode. You have this:

//...

i2c_EnableAck();

i = I2C1_D ; // Dummy read 

i2c_Wait();

DMA_starttransfer(DMA_BASE_PTR,0, 14);

But it should be like this:

//...

i2c_EnableAck();

DMA_starttransfer(DMA_BASE_PTR,0, 14);

i = I2C1_D ; // Dummy read

//...

The best way to debug I2C issues is to scan the bus with an oscilloscope or a logic analyzer, so you can see what exact transfers are being made or are missing.


Regards!,
Jorge Gonzalez

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos
Reply