cancel
Showing results for 
Search instead for 
Did you mean: 

i2c dma transmit/receive multiple bytes

abhinav
Associate II
Posted on August 13, 2014 at 17:46

I am trying to transmit multiple bytes on I2C bus using dma. In the sample code I am trying to send 3 bytes. I see on my scope that three bytes are being sent but the problem is that the first byte gets sent three times. I am also able to recive three bytes without any problem but agian nothing gets written in the location of the second and third byte.

I generated the code using CubeMX but modified the main file to send/recieve at the right time. My master transmitter code looks like this:

#define

 

i2c_buffer_size 3

 

uint8_t

i2c_data_buffer[i2c_buffer_size] = {0x03,0x10,

0xFF};

 

uint16_t slaveAddress =

0x05;

 

....

 

void

cmd_send_i2c(

){

 

HAL_I2C_Master_Transmit_DMA(&hi2c1, slaveAddress,i2c_data_buffer, i2c_buffer_size);

 

}

 

My slave receiver code looks like this

 

</p>

 

int

 

</b>

 

 

main(

void

){

 

/* Reset of all peripherals, Initializes the Flash interface and the

Systick

. */

 

HAL_Init();

 

/* Initialize all configured peripherals */

 

MX_GPIO_Init();

 

MX_DMA_Init();

 

MX_I2C1_Init();

 

while

(1)

 

{

 

if

(HAL_I2C_GetState(&hi2c1)==

HAL_I2C_STATE_READY

)

 

HAL_I2C_Slave_Receive_DMA(&hi2c1,(

uint8_t

*) i2c_data_buffer,i2c_buffer_size);

 

}

 

return

0;

 

}

 

 

and the receive call back function is

 

 

void

 

 

 

HAL_I2C_SlaveRxCpltCallback(

I2C_HandleTypeDef

*hi2c){

 

LED_RED_TOGGLE;

 

if

(i2c_data_buffer[0] == 0x03)

 

    

LED_BLUE_TOGGLE;

 

if

(i2c_data_buffer[1] == 0x10)

 

    LED_GREEN_TOGGLE;

 

return

;

 

}

 

I am checking the i2c_data_buffer using a debugger and the value for i2c_data_buffer[0] is correct but i2c_data_buffer[1] is not correct.

 

 

Thanks in advance for the help!
5 REPLIES 5
jwoolston
Associate II
Posted on August 13, 2014 at 17:57

Can you show the contents of the HAL_DMA_Init() method? I'm assuming the DMA is not configured to auto increment the memory location or your data width is perhaps incorrect.

jwoolston
Associate II
Posted on August 13, 2014 at 17:58

MX_I2C1_Init as well please

abhinav
Associate II
Posted on August 13, 2014 at 19:01

Please see below functions HAL_DMA_Init, MX_I2C1_Init and MX_DMA_Init. I am also adding the code snippet for the DMA peripheral initialization from the function HAL_I2C_MspInit.

Thanks a lot for looking at this code!

HAL_StatusTypeDef

HAL_DMA_Init(

DMA_HandleTypeDef

*hdma)

{

uint32_t

tmp = 0;

/* Check the DMA handle allocation */

if

(hdma == NULL)

{

return

HAL_ERROR

;

}

/* Check the parameters */

assert_param(IS_DMA_ALL_INSTANCE(hdma->

Instance

));

assert_param(IS_DMA_DIRECTION(hdma->

Init

.

Direction

));

assert_param(IS_DMA_PERIPHERAL_INC_STATE(hdma->

Init

.

PeriphInc

));

assert_param(IS_DMA_MEMORY_INC_STATE(hdma->

Init

.

MemInc

));

assert_param(IS_DMA_PERIPHERAL_DATA_SIZE(hdma->

Init

.

PeriphDataAlignment

));

assert_param(IS_DMA_MEMORY_DATA_SIZE(hdma->

Init

.

MemDataAlignment

));

assert_param(IS_DMA_MODE(hdma->

Init

.

Mode

));

assert_param(IS_DMA_PRIORITY(hdma->

Init

.

Priority

));

/* Change DMA peripheral state */

hdma->

State

=

HAL_DMA_STATE_BUSY

;

/* Get the CR register value */

tmp = hdma->

Instance

->

CCR

;

/* Clear PL, MSIZE, PSIZE, MINC, PINC, CIRC, DIR bits */

tmp &= ((

uint32_t

)~(DMA_CCR_PL | DMA_CCR_MSIZE | DMA_CCR_PSIZE | \

    DMA_CCR_MINC | DMA_CCR_PINC | DMA_CCR_CIRC | \

    DMA_CCR_DIR));

/* Prepare the DMA Channel configuration */

tmp |= hdma->

Init

.

Direction

|

    hdma->

Init

.

PeriphInc

| hdma->

Init

.

MemInc

|

    hdma->

Init

.

PeriphDataAlignment

| hdma->

Init

.

MemDataAlignment

|

    hdma->

Init

.

Mode

| hdma->

Init

.

Priority

;

    /* Write to DMA Channel CR register */

hdma->

Instance

->

CCR

= tmp;

/*

Initialise

the error code */

hdma->

ErrorCode

= HAL_DMA_ERROR_NONE;

/* Initialize the DMA state*/

hdma->

State

=

HAL_DMA_STATE_READY

;

return

HAL_OK

;

}

/* I2C1

init

function */

void

MX_I2C1_Init(

void

)

{

hi2c1.

Instance

= I2C1;

hi2c1.

Init

.

Timing

= 0x2000090E;

hi2c1.

Init

.

OwnAddress1

= 0x05;

hi2c1.

Init

.

AddressingMode

= I2C_ADDRESSINGMODE_7BIT;

hi2c1.

Init

.

DualAddressMode

= I2C_DUALADDRESS_DISABLED;

hi2c1.

Init

.

OwnAddress2

= 0;

hi2c1.

Init

.

OwnAddress2Masks

= I2C_OA2_NOMASK;

hi2c1.

Init

.

GeneralCallMode

= I2C_GENERALCALL_DISABLED;

hi2c1.

Init

.

NoStretchMode

= I2C_NOSTRETCH_DISABLED;

HAL_I2C_Init(&hi2c1);

/**Configure

Analogue

filter

*/

HAL_I2CEx_AnalogFilter_Config(&hi2c1, I2C_ANALOGFILTER_ENABLED);

}

 

void

MX_DMA_Init(

void

)

{

/* DMA controller clock enable */

__DMA1_CLK_ENABLE();

/* DMA interrupt

init

*/

/* Sets the priority grouping field */

HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_0);

HAL_NVIC_SetPriority(

DMA1_Channel6_IRQn

, 0, 0);

HAL_NVIC_EnableIRQ(

DMA1_Channel6_IRQn

);

/* Sets the priority grouping field */

HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_0);

HAL_NVIC_SetPriority(

DMA1_Channel7_IRQn

, 0, 0);

HAL_NVIC_EnableIRQ(

DMA1_Channel7_IRQn

);

}

From HAL_I2C_MspInit

hdma_i2c1_tx.

Instance

= DMA1_Channel6;

hdma_i2c1_tx.

Init

.

Direction

= DMA_MEMORY_TO_PERIPH;

hdma_i2c1_tx.

Init

.

PeriphInc

= DMA_PINC_DISABLE;

hdma_i2c1_tx.

Init

.

MemInc

= DMA_MINC_DISABLE;

hdma_i2c1_tx.

Init

.

PeriphDataAlignment

= DMA_PDATAALIGN_BYTE;

hdma_i2c1_tx.

Init

.

MemDataAlignment

= DMA_MDATAALIGN_BYTE;

hdma_i2c1_tx.

Init

.

Mode

= DMA_NORMAL;

hdma_i2c1_tx.

Init

.

Priority

= DMA_PRIORITY_LOW;

HAL_DMA_Init(&hdma_i2c1_tx);

jwoolston
Associate II
Posted on August 13, 2014 at 19:09

As I thought, the DMA is not configured to increment the memory location. Change

hdma_i2c1_tx.Init.MemInc = DMA_MINC_DISABLE;

To:

hdma_i2c1_tx.Init.MemInc = DMA_MINC_ENABLE;

And you should be good.
abhinav
Associate II
Posted on August 13, 2014 at 19:16

Thanks a lot for the help. It is working fine now!