TWIM Buffer Behavior When Debugging vs. Not Debugging

Hello All,

I am experiencing strange results when using the TWIM peripheral with and without using the debugger. 

Setup:

  • Keil IDE for development and debugging - V5.26.2.0
  • DK - pca10040 (nRF52832)
  • Softdevice - s132 V7.2.0
  • SDK - V17.1.0

Scenario:

pca10040 is connected via SCL & SDA to an Arduino which is printing the incoming I2C buffer out onto the Serial Monitor. Running at 400k.

Sending 3 data bytes over I2C line every 2 seconds: 0x04, 0x33, 0x22

Issue:

I have confirmed buffer integrity all the way to the "nrf_twim_task_trigger(p_twim, start_task)" call within the nrfx_twim.c file.

Without placing any break points, I receive this on the Serial Monitor: 0x04 - 0x33 - 0x00  (The "-" is just a delimiter being printed on the Arduino side)

If I place a breakpoint at the conditional check that triggers the TWIM send:

if (!(flags & NRFX_TWIM_FLAG_HOLD_XFER) && (p_xfer_desc->type != NRFX_TWIM_XFER_TXTX))
{
    nrf_twim_task_trigger(p_twim, start_task);
}

I can step through the code and the expected 0x04 - 0x33 - 0x22 comes through on the Serial Monitor, every single time.

My question is what is the difference between simply executing the code and stepping through each line, and why would that result in different outcomes on the I2C line? Another important note is that any buffer length less than three bytes comes through correct. Any buffer length greater than or equal to three results in this issue where the 3rd byte of data, and every byte afterwards, is a zero. I am receiving no error codes to indicated a problem.

I have enabled the workaround within the TWIM xfer function (Anomaly 109) as well as attempting some of the other solutions detailed in the Anomaly 109 documentation with no luck. 

I've also attempted delays and timers to hold code execution just above the nrf_twim_task_trigger call to simulate the pause that would occur when setting a breakpoint. 

If I've missed any important information to help solve the issue, please let me know. Any help is appreciated. 

Thank you,

-Cody

  • Hi,

    Can you post the code used for sending data through the TWIM peripheral?

    Have you made sure that the buffer is in scope during the full transfer, to make sure nothing else in the application overwrites the stack area before the transfer is completed?

    Best regards,
    Jørgen

  • Hi Jorgen,

    Data buffer setup, where "bank1"  is a structure containing a uint8_t array "data" of length equal to 3.

    pcs_wire_inst *bank1 = (pcs_wire_inst*)malloc(sizeof(pcs_wire_inst));
    static uint16_t debugData = 0x2233;
    bank1->data[0] = (uint8_t)(0x04);                       //0x04
    bank1->data[1] = (uint8_t)(debugData & 0xFF);           //0x33
    bank1->data[2] = (uint8_t)((debugData >> 8) & 0xFF);    //0x22

    Access function to TWIM peripheral: 

    wire_pcs_write(0x3C, bank1->data, sizeof(bank1->data));

    Function def:

    uint32_t wire_pcs_write(uint8_t target_address, uint8_t const *data, size_t size)
    {
    	uint32_t err_code;
    	uint8_t buffer[size];											//temp buffer for data
    	memcpy(buffer, data, size);								//place incoming data into buffer
    	
    	err_code = nrfx_twim_tx(&m_twim, target_address, buffer, sizeof(buffer), false);
    	return err_code;			//will return 0 if successful
    }

    Following the nrfx_twim_tx function all the way to task trigger...

    As seen above, p_xfer_desc's buffer contains all three bytes of data. At this point, if I execute one step through the code I get 0x04 - 0x33 - 0x22 on my Arduino Serial Monitor. However, if I do not place a breakpoint here and simply let the code execute, the last byte is always 0x00 on the Serial Monitor. Again, I can simply change the length of the "data" buffer from 3 to 2 bytes, and everything works fine but my application requires 3 bytes minimum.

    Am I misunderstanding where the data is actually contained, not in p_xfer_desc primary buffer?

    Thank you for your help.

    -Cody

  • Hi,

    The data is not stored in p_xfer_desc, this is just a pointer to the RAM buffer where the data is actually stored.

    In your wire_pcs_write function, you are copying the data from "data" pointer to a local "buffer" array. This buffer is not global or static, and will be stored on the stack. Once you exit the function call, the memory area of the "buffer" will be released back to the stack and can be used by other function calls. nrfx_twim_tx() is a async function, which starts the transfer, but the transfer will likely not finish before you have exited the wire_pcs_write() function. This means that other parts of your application can overwrite the data before the transfers is done with accessing the data in RAM.

    Try to declare the "buffer" array as static, to prevent it from being overwritten when you exit the function, or move it's declaration to the global application scope.

    Best regards,
    Jørgen

Related