AnsweredAssumed Answered

Missing first byte over I2C on STM32F3Discovery Board

Question asked by bateman.brent on Mar 14, 2015
I am trying to port the CMUCAM5 Pixy I2C libraries over from Arduino over to an STM32F3Discovery board.  I have worked through several problems but now I am stuck with an issue where the first byte after the master requests data is coming up as all zeros.  The issue is also intermittent.  The Pixy device sends 0xaa55, 0xaa55 at the beginning of a frame of video processing and I am getting 0x0055, 0xaa55 and I cannot figure out why.  The library works just fine on the arduino and I notice on the scope that the clock is held low for almost a whole clock cycle after the master command to read data is sent and acknowledged.  When the Pixy is hooked up to the STM32F3discovery board there is no interruption of the constant stream of clock cycles.  At first I thought it might be the Pixy using Clock Stretching but I confirmed with the manufacturer that the Pixy does not use clock stretching.  Here are screen captures of the two different boards attached to the pixy.  You can see with the arduino that at about the middle of the screen there is a pause in the clock cycles.  Can you make the STM32F3 add a delay like this with the clock pulled low?  Or am I doing something else incorrectly.  Here is my code:

/* Includes ------------------------------------------------------------------*/
#include "Pixy_STM32F3Disc.h"
#include <stdio.h>
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
 
#define I2C_TIMEOUT  0x8000
static BlockType g_blockType; // use this to remember the next object block type between function calls
static Block *g_blocks;
static int g_skipStart = 0;
extern Block m_blocks[];
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
 
uint8_t Block_Init(void)
{
    g_blocks = m_blocks;
 
  return 1;
}
 
uint16_t getBlocks(uint16_t maxBlocks)
{
  uint8_t i;
  uint16_t w, blockCount, checksum, sum;
  Block *block;
 
  if (!g_skipStart)
  {
    if (getStart(I2C1,PIXY_DEFAULT_ADDR)==0)
      return 0;
  }
  else
    g_skipStart = 0;
 
  for(blockCount=0; blockCount<maxBlocks && blockCount<PIXY_INITIAL_ARRAYSIZE;)
  {
    checksum = getWord(I2C1,PIXY_DEFAULT_ADDR);
    if (checksum==PIXY_START_WORD) // we've reached the beginning of the next frame
    {
      g_skipStart = 1;
      g_blockType = NORMAL_BLOCK;
      return blockCount;
    }
    else if (checksum==PIXY_START_WORD_CC)
    {
      g_skipStart = 1;
      g_blockType = CC_BLOCK;
      return blockCount;
    }
    else if (checksum==0)
      return blockCount;
 
    block = g_blocks + blockCount;
 
    for (i=0, sum=0; i<sizeof(Block)/sizeof(uint16_t); i++)
    {
      if (g_blockType==NORMAL_BLOCK && i>=5) // no angle for normal block
      {
        block->angle = 0;
        break;
      }
      w = getWord(I2C1,PIXY_DEFAULT_ADDR);
      sum += w;
      *((uint16_t *)block + i) = w;
    }
 
    // check checksum
    if (checksum==sum)
      blockCount++;
    else
    printf("checksum error!\n");
 
    w = getWord(I2C1,PIXY_DEFAULT_ADDR);
 
    if (w==PIXY_START_WORD)
      g_blockType = NORMAL_BLOCK;
    else if (w==PIXY_START_WORD_CC)
      g_blockType = CC_BLOCK;
    else
    {
        return blockCount;
    }
  }
  return 0;
}
 
uint8_t getByte(I2C_TypeDef* I2Cx, volatile uint8_t DeviceAddr)
{
  uint8_t c;
  printf("GetByte Call\n\r");
  PixyI2Cx_read(I2Cx, DeviceAddr, &c, 1);
  return c;
}
 
uint8_t getStart(I2C_TypeDef* I2Cx, uint8_t DeviceAddr)
{
  uint16_t w, lastw;
 
  lastw = 0xffff; // some inconsequential initial value
  w = getWord(I2Cx, DeviceAddr);
  while(1)
  {
    w = getWord(I2Cx, DeviceAddr);
 
    if (w==0 && lastw==0)
    {
        //printf("\n\r Returned Zero word is:%#6x",w);
        return 0; // in I2C and SPI modes this means no data, so return immediately
    }
    else if (w==PIXY_START_WORD && lastw==PIXY_START_WORD)
    {
      g_blockType = NORMAL_BLOCK; // remember block type
      return 1; // code found!
    }
    else if (w==PIXY_START_WORD_CC && lastw==PIXY_START_WORD)
    {
      g_blockType = CC_BLOCK; // found color code block
      return 1;
    }
    else if (w==PIXY_START_WORDX) // this is important, we might be juxtaposed
        getByte(I2Cx,DeviceAddr); // we're out of sync! (backwards)
    lastw = w; // save
  }
  return 0;
}
 
uint16_t getWord(I2C_TypeDef* I2Cx, uint8_t DeviceAddr)
{
  // this routine assumes little endian
  volatile uint16_t w;
  static uint8_t c[2]={0,0};
  uint8_t results;
  results = PixyI2Cx_read(I2Cx, DeviceAddr, c, 2);
  w=0;
  w = (c[0])<<8;
  //w <<= 8;
  w |= c[1];
  printf("\n\r%#6x",w);
  return w;
}
 
void Pixy_I2C_Initialize()
{
    I2C_InitTypeDef         I2C_InitStruct;
    GPIO_InitTypeDef        GPIO_InitStruct;
 
    /* GPIOB Periph clock enable */
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
    /* I2C1 Periph clock enable */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
    I2C_Cmd(I2C1, DISABLE);
    /* GPIO configuration */
    /* Configure I2C pin: SCL on PB6 */
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_Init(GPIOB, &GPIO_InitStruct);
 
    /* Configure I2C pins: SDA on PB7 */
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7;
    GPIO_Init(GPIOB, &GPIO_InitStruct);
 
    /* Connect PB6 to I2C_SCL*/
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_4);
 
    /* Connect PB7 to I2C_SDA*/
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_4);
 
    /* Configure the I2C clock source. The clock is derived from the SYSCLK */
    RCC_I2CCLKConfig(RCC_I2C1CLK_SYSCLK);
 
    /*******************************************/
    I2C_DeInit(I2C1);
    I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;
    I2C_InitStruct.I2C_AnalogFilter = I2C_AnalogFilter_Disable;
    I2C_InitStruct.I2C_DigitalFilter = 0x00;
    I2C_InitStruct.I2C_OwnAddress1 = 0x00;
    I2C_InitStruct.I2C_Ack = I2C_Ack_Enable;
    I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
 
    I2C_InitStruct.I2C_Timing =0xA061191F; //800ns rise time and 180ns fall time and 100kHz Clk;
     /*****************************************/
 
    I2C_Init(I2C1, &I2C_InitStruct);
    I2C_Cmd(I2C1, ENABLE);
}
 
uint8_t PixyI2Cx_read(I2C_TypeDef* I2Cx, uint8_t DeviceAddr, uint8_t* TempBuffer, uint16_t len)
{
  /* Test on BUSY Flag */
  uint32_t timeout = I2C_TIMEOUT;
 
  while(I2C_GetFlagStatus(I2Cx, I2C_ISR_BUSY) != RESET)
  {
 
    if((timeout--) == 0)
    {
        return 0;
    }
  }
 
  /***************************************************************************/
  /**** Comment out original method of attempting to read in replace with I2C simple events
   *    i.e. start, send command, read, read, stop
   **********************************************************************************
   */
  /*
  // Configure slave address, nbytes, reload, end mode and start or stop generation
  I2C_TransferHandling(I2Cx, DeviceAddr, 2, I2C_AutoEnd_Mode, I2C_Generate_Start_Read);
 
  */
  /*****************Start new attempt at I2C communication ***************/
  I2C_SlaveAddressConfig(I2Cx, DeviceAddr);
  I2C_MasterRequestConfig(I2Cx, I2C_Direction_Receiver);
  I2C_NumberOfBytesConfig(I2Cx, len); // number of bytes to receive
  I2C_GenerateSTART(I2Cx, ENABLE);
  //I2C_NumberOfBytesConfig(I2Cx, len); // number of bytes to receive
 
  /* Wait until all data are received */
  while (len)
  {
  /* Wait until RXNE flag is set */
    timeout = I2C_TIMEOUT;
    while(I2C_GetFlagStatus(I2Cx, I2C_ISR_RXNE) == RESET)
    {
      if((timeout--) == 0)
          {
          printf("\n\rTimedOutWaitingForReceive");
          return 0;
          }
    }
  /* Read data from RXDR */
    *TempBuffer = I2C_ReceiveData(I2Cx);
 
    //printf("\n\r Byte %d Just Read: %#4x with ",(2-len),*TempBuffer);
/* Point to the next location where the byte read will be saved */
    TempBuffer++;
 
    /* Decrement the read bytes counter */
    len--;
  }
  /* Wait until STOPF flag is set */
  I2C_GenerateSTOP(I2Cx, ENABLE);
  timeout = I2C_TIMEOUT;
  while(I2C_GetFlagStatus(I2Cx, I2C_ISR_STOPF) == RESET)
  {
    if((timeout--) == 0) return 0;
  }
 
  /* Clear STOPF flag */
  I2C_ClearFlag(I2Cx, I2C_ICR_STOPCF);
 
  /* If all operations OK */
  return 1;
}

 

Outcomes