MediaTek-Labs / mt3620_m4_software

mt3620_m4_driver
Other
32 stars 29 forks source link

I2C on baremetal #25

Closed bax78 closed 4 years ago

bax78 commented 4 years ago

Having problems getting the I2C ISU2 working. The FreeRTOS I2C example is working perfectly, but when trying to implement os_hal_i2c.h on the BareMetal_HelloWorld example it fails and end up in this loop:

while (ctrl_rtos->xfer_completion == 0) {
        if (sys_tick_in_ms - start_tick > time_ms)
            return -1;

The sys_tick_in_ms is not getting updated and it's stuck.

Init:

ret = mtk_os_hal_i2c_ctrl_init(i2c_master_port_num);
ret = mtk_os_hal_i2c_speed_init(i2c_master_port_num, i2c_master_speed);

Read:

int i2c_read_reg(uint8_t reg_addr, uint8_t* reg_data)
{
    int ret;
    uint8_t write_buf[1] = { 0 };
    uint8_t read_buf[1] = { 0 };

    write_buf[0] = reg_addr;
    ret = mtk_os_hal_i2c_write_read(i2c_master_port_num, 0x40, write_buf, read_buf, 1, 1);
    if (ret == 0)
        *reg_data = read_buf[0];

    return ret;
}

Printf error:

data_len 1, read_len 0, fifo read error
i2c2 write fail

Clearly I've missed something?

Thanks !

kevinwh-chou commented 4 years ago

Hi,

Can you check in app_manifest.json, is I2cMaster correctly set to ISU2 like the following as you mentioned that you worked with I2C ISU2?

"Capabilities": { "I2cMaster": [ "ISU2" ], },

If it's not set, the IRQ handler at ISU2 won't be correctly enabled which results in getting stuck in that while loop.

bax78 commented 4 years ago

Hi Kevin

Thanks for your reply. My app_manifest.json is set correctly:

"I2cMaster": [ "ISU2" ],

I discovered something new going through the Call Stack when the crash happens. I was trickering a I2C read within a GPT timer loop which messed up alle other interrupts I guess (even the tick interrupt is not triggered). So if I read the I2C from the main loop instead using the GPT to trigger (poormans semaphore), then I got it to work!

The FreeRTOS implements the Semaphore to protect the IRQ and hardware I guess, but using the OS_HAL framework as baremetal lacks this maybe (?)

kevinwh-chou commented 4 years ago

Hi bax78,

Thanks for the update! In baremetal case, did you call the I2C read within GPT callback function, namely gpt_cb_hdl in the struct os_gpt_int?

struct os_gpt_int { /* The user interrupt handle of GPT. / void (gpt_cb_hdl)(void ); /** The pointer of GPT interrupt callback data, which will be passed

And just to be sure, did you also do the same thing for FreeRTOS (i.e. in GPT callback executing I2C read) and turned out it worked well?

bax78 commented 4 years ago

Yes running from within the *gpt_cb_data. Using the BareMetal_HelloWorld example I created one function to read from I2C and used the Callback function to execute it fails:

int i2c_read_reg(uint8_t reg_addr, uint16_t* reg_data)
{
    int ret;
    uint8_t write_buf[1] = { 0 };
    uint8_t read_buf[2] = { 0 };

    write_buf[0] = reg_addr;
    ret = mtk_os_hal_i2c_write_read(i2c_master_port_num, 0x40, write_buf, read_buf, 1, 2);
    if (ret == 0)
        *reg_data = read_buf[1] | (uint16_t)read_buf[0] << 8;

    return ret;
}

static void Gpt0Callback(void *cb_data)
{
    static uint8_t print_counter;
    uint16_t reg_data = 0;

    i2c_read_reg(0xfe, &reg_data);
    if (reg_data == 0x5449) {
        printf("%d\n", reg_data);
    }
}

It's working using i2c_read_reg function within main instead:

static void Gpt0Callback(void* cb_data)
{
    static uint8_t print_counter;

    if (print_counter++ >= 500) {
        runApp = 1;
    }
}

in main:

for (;;) {
        __asm__("wfi");
        if (runApp) {
            i2c_read_reg(0xfe, &reg_data);
            if (reg_data == 0x5449) {
                printf("%d\n", reg_data);
            }

            runApp = 0;
        }

    }

In FreeRTOS I'm just using the example i2c_master_task and not using the Timer.

kevinwh-chou commented 4 years ago

Hi bax78,

Thanks for the feedback.

The cause for this issue should be that by default GPT and I2C has the same NVIC priority, as I2C IRQ is triggered by calling I2C API function in GPT callback function (GPT ISR), I2C ISR won't be handled due to the same priority. Then it ends up in getting stuck in _mtk_os_hal_i2c_wait_for_completion_timeout(). Reading the I2C IRQ status to be pending in GPT ISR should help confirm that, and the same thing is supposed to occur in FreeRTOS.

The way to achieve the application you want should be like what you've done in main, the latter case.