]> granicus.if.org Git - esp-idf/commitdiff
bugfix: i2c driver not working in 'RELEASE' configuration
authorWangjialin <wangjialin@espressif.com>
Sun, 19 Mar 2017 08:09:44 +0000 (16:09 +0800)
committerWangjialin <wangjialin@espressif.com>
Sun, 19 Mar 2017 08:09:44 +0000 (16:09 +0800)
This issue is reported from https://github.com/espressif/esp-idf/issues/304.
We found that when we operate the hw command registers in I2C struct, sometimes the behaviour would be different in DEBUG/RELEASE optimisation level:

The code looks like this:
I2C[i2c_num]->command[p_i2c->cmd_idx].byte_num -= 0;

In DEBUG configuration:
I2C[i2c_num]->command[p_i2c->cmd_idx].byte_num -= 0;
400f3ab0:    3388          l32i.n    a8, a3, 12
400f3ab2:    14c882            addi    a8, a8, 20
400f3ab5:    a08840            addx4    a8, a8, a4
400f3ab8:    0020c0            memw
400f3abb:    2898          l32i.n    a9, a8, 8
400f3abd:    0020c0            memw
400f3ac0:    28b8          l32i.n    a11, a8, 8
400f3ac2:    74a090            extui    a10, a9, 0, 8
400f3ac5:    00af92            movi    a9, 0xffffff00
400f3ac8:    109b90            and    a9, a11, a9
400f3acb:    2099a0            or    a9, a9, a10
400f3ace:    0020c0            memw
400f3ad1:    2899          s32i.n    a9, a8, 8

In RELEASE configuration:
I2C[i2c_num]->command[p_i2c->cmd_idx].byte_num -= 0;
400f2ba2:    580572            l8ui    a7, a5, 88
400f2ba5:    747070            extui    a7, a7, 0, 8
400f2ba8:    0020c0            memw
400f2bab:    584572            s8i    a7, a5, 88

Looks like the compiler will make it a 8bit operation after optimisation.
But the register value changes from 0x901 to 0x101.
After this 8-bit optimisation, the 11th bit changed from 1 to zero, which caused this error.

We are still trying to find out why that happens, because there might be some risk when operating the register struct.
This is a workaround to avoid "-=" operation on I2C register struct fields.

components/driver/i2c.c

index 39eb877349fe7def6cf5930f77f03d2f9b44bf10..adfcfe7bf3b493439ce37e5f4bc643c00e0cf14f 100644 (file)
@@ -862,19 +862,23 @@ static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num)
         I2C[i2c_num]->command[p_i2c->cmd_idx].byte_num = cmd->byte_num;\r
         I2C[i2c_num]->command[p_i2c->cmd_idx].op_code = cmd->op_code;\r
         if (cmd->op_code == I2C_CMD_WRITE) {\r
+            uint32_t wr_filled = 0;\r
             //TODO: to reduce interrupt number\r
             if (cmd->data) {\r
                 while (p_i2c->tx_fifo_remain > 0 && cmd->byte_num > 0) {\r
                     WRITE_PERI_REG(I2C_DATA_APB_REG(i2c_num), *cmd->data++);\r
                     p_i2c->tx_fifo_remain--;\r
                     cmd->byte_num--;\r
+                    wr_filled++;\r
                 }\r
             } else {\r
                 WRITE_PERI_REG(I2C_DATA_APB_REG(i2c_num), cmd->byte_cmd);\r
                 p_i2c->tx_fifo_remain--;\r
                 cmd->byte_num--;\r
+                wr_filled ++;\r
             }\r
-            I2C[i2c_num]->command[p_i2c->cmd_idx].byte_num -= cmd->byte_num;\r
+            //Workaround for register field operation.\r
+            I2C[i2c_num]->command[p_i2c->cmd_idx].byte_num = wr_filled;\r
             I2C[i2c_num]->command[p_i2c->cmd_idx + 1].val = 0;\r
             I2C[i2c_num]->command[p_i2c->cmd_idx + 1].op_code = I2C_CMD_END;\r
             p_i2c->tx_fifo_remain = I2C_FIFO_LEN;\r