i2c on arm9 causing data abort

bones23 wrote on Friday, December 28, 2007:

I am trying to get an i2c driver running in freeRTOS on an str912. All it does right now is send a message continuously from the arm9 to a test device I have hooked up to the i2c bus. The i2c thread will run several hundred times just fine but will then throw a Prefetch abort. After stepping through the program I found that this happens in the call to vTaskDelay() made after the call to I2C_WriteData() has finished. Any ideas on what could be causing this?

//i2c thread
void prvRunI2C(void){
  u8 i2cmsg[] = "test";
 
  for(;;){
    I2C_WriteData(0x6e, i2cmsg, 4);
    vTaskDelay( mainLCD_DELAY );
  }
}

//I2C_WriteData()
void I2C_WriteData(u8 address, u8 *msg, u8 count)
{
  portENTER_CRITICAL();
  I2C0_Buffer_Tx= msg;
  i2c_buffer_size=count;
  i2c_slave_address = address;

  Direction = I2C_MODE_TRANSMITTER;
  Tx_Idx=0;

  {
    char hex1[3];
    char hex2[3];
    char hex3[3];
    hex1[2] = hex2[2] = hex3[2] = 0;

    byte2hex(I2C0_Buffer_Tx[0], hex1);
    byte2hex(I2C0_Buffer_Tx[1], hex2);
    byte2hex(I2C0_Buffer_Tx[2], hex3);
  }

  I2C_GenerateStart(I2C0, ENABLE);
/* Test on EV5 and clear it */
  while( ! I2C_CheckEvent(I2C0, I2C_EVENT_MASTER_MODE_SELECT) )  // EV5
    {;
    }
  /* Send I2C1 Address for write */
  I2C_Send7bitAddress (I2C0, i2c_slave_address, I2C_MODE_TRANSMITTER);
  /* Test on EV6 and clear it */
  while( ! I2C_CheckEvent(I2C0, I2C_EVENT_MASTER_MODE_SELECTED) );  // EV6
  /* Clear EV6 by set again the PE bit */
  I2C_Cmd (I2C0, ENABLE);
  /* Send Data to write on I2C1 slave */
  while (Tx_Idx < i2c_buffer_size)// && !stop)
  {
    /*snprintf(out_buf, 80, "sending byte: %d\r\n", Tx_Idx);
    send_data(DEBUG_UART, out_buf, strlen(out_buf) );
    */

    /* Send Master data */
   
    I2C_SendData(I2C0, I2C0_Buffer_Tx[Tx_Idx++]);
    /* Test on EV8 and clear it */
    while(!I2C_CheckEvent(I2C0, I2C_EVENT_MASTER_BYTE_TRANSMITTED))//  && !stop)  //EV8
      {
    u16  wLastEvent = I2C_GetLastEvent(I2C0);
   
    switch (wLastEvent)
      {
        /* 16 means that the BUSY flag is set, but not the M/SL flag. 
           Since we mean to act only as a master, the M/SL flag should be
           set anytime we are in the middle of transmission*/
        /*case 16:
        stop = 1;
        snprintf(out_buf, 80, "I2C Error, wLastEvent==16\r\n");
        send_data(DEBUG_UART, out_buf, strlen(out_buf));
        if (wLastEvent == I2C_ARBITRATION_LOST)
          {
        snprintf(out_buf, 80, "I2C Arbitration Lost\r\n");
        send_data(DEBUG_UART, out_buf, strlen(out_buf));
        stop=1; //Leave the while loop
          }
        if (wLastEvent == I2C_BUS_ERROR_DETECTED)
          {
        snprintf(out_buf, 80, "I2C Bus Error\r\n");
        send_data(DEBUG_UART, out_buf, strlen(out_buf));
        stop=1; //Leave the while loop
          }
        break;
      case 0:
        snprintf(out_buf, 80, "I2C status of 0, stopping\r\n");
        send_data(DEBUG_UART, out_buf, strlen(out_buf));
        stop = 1;
        break;*/
        CASE_ERROR(I2C_EVENT_SLAVE_ADDRESS_MATCHED)
          CASE_ERROR(I2C_EVENT_SLAVE_BYTE_RECEIVED)
          CASE_ERROR(I2C_EVENT_SLAVE_BYTE_TRANSMITTED)
          CASE_ERROR(I2C_EVENT_MASTER_MODE_SELECT)
          CASE_ERROR(I2C_EVENT_MASTER_MODE_SELECTED)
          CASE_ERROR(I2C_EVENT_MASTER_BYTE_RECEIVED)
          //CASE_ERROR(I2C_EVENT_MASTER_BYTE_TRANSMITTED)
      case I2C_EVENT_MASTER_BYTE_TRANSMITTED:
        break;
          CASE_ERROR(I2C_EVENT_MASTER_MODE_ADDRESS10)
          CASE_ERROR(I2C_EVENT_SLAVE_STOP_DETECTED)
          CASE_ERROR(I2C_EVENT_SLAVE_ACK_FAILURE)
      case 18: /*This is the correct busy state, busy flag, plus m/sl flag*/
        break;
      default:
        UART_printf(DEBUG_UART, "unknown event: %d on byte: %d\r\n", wLastEvent, Tx_Idx);
        break;
      }
      }
  }
 
  /* Generate STOP condition to close communication */
  I2C_GenerateSTOP (I2C0, ENABLE);
  /* Disable I2C0 */
  //I2C_Cmd(I2C0, DISABLE);
  portEXIT_CRITICAL();
}

rtel wrote on Sunday, December 30, 2007:

Have you checked that you are not running out of stack?  I notice you are using snprintf() which can take up a lot of stack space.

First of all try simply increasing the stack allocated to the task.

Next you could try actually inspecting the stack.  When the abort happens, inspect the pxCurrentTCB variable to see which task was running.  From the structure you will be able to get the location of the stack the task was using.  The stack was filled with 0xa5 when the task was created, so if all the 0xa5’s have been overwritten then you know you are out of stack.

There are some cut down versions of the printf() family of functions included in the FreeRTOS.org download.

Regards.

bones23 wrote on Tuesday, January 15, 2008:

Your right, I did not give this one enough stack space.