SigmaStudioFW

SigmaStudioFW.h

If you look at the default SigmaStudioFW.h file you’ll notice that Analog Devices left a lot to be done. The first part I tackled was the SIGMA_WRITE_REGISTER_BLOCK function:

 

void SIGMA_WRITE_REGISTER_BLOCK(int devAddress, int address, int length, ADI_REG_TYPE *pData ) 
{
 
  int ii = 0;
  int zz = 0;
  char filename[20];
  Tx_Idx = 0;
 
     deviceHandle = open("/dev/i2c-0", O_RDWR);
 
   if(deviceHandle < 0) //if there was a problem opening the file
    {
     //print("\n could not open file \n");
     return;
    }
 
  // connect to DSP address
  int deviceI2CAddress = (devAddress >> 1); //DEVICE_ADDR_IC_1 found in *_IC_1.h needs to be shifted right 1 bit 
 
  //setup the device and check for errors
  if(ioctl(deviceHandle, I2C_SLAVE, deviceI2CAddress) < 0)
  {
   //print("\n ioctl failed \n");
   return;
  }
 
/*----- Transmission Phase -----*/
    ThisBufferSize = Address_Length + length; //2 bytes for the address + the length of the data packet
 
    I2C1_Buffer_Tx[0] =   (address & 0xFF00)>>8; //mask the upper 8 bits of the address then put into unique variable
    I2C1_Buffer_Tx[1] =   address & 0x00FF; //mask the lower 8 bits of the address then put into unique variable
 
    for(zz=0;zz<length;zz++)
        {
        I2C1_Buffer_Tx [zz + Address_Length] =   pData[zz]; //fill the buffer array with the data (still leaving room for the address)
        }
 
  // begin transmission and request acknowledgement
  write(deviceHandle, I2C1_Buffer_Tx, ThisBufferSize); //send it out the port
 
    // close connection and return
  close(deviceHandle);
  return;
}

 

This function is 1 of 2 core functions (the other being SIGMA_READ_REGISTER).
It starts out opening a new device handle for the transmission. It then prepares the data. You’ll notice that I cut off the last bit of the DSP I2C address that is provided in the *_IC_1.h file; this was done because the given address is the full 8 bit address, and the way the raspberry pi handles the ioctl function it expects the 7 bit address (the R/W bit is not included, the drivers take care of this for us). Next we open up the port using ioctl. You’ll see a lot of commented out printf statements that I used for troubleshooting. Once we know the port is ready we begin to fill the transmission buffer with the actual data. The first 2 elements of the transmission buffer are the address split into high and low bytes. Then it is filled with the actual data (which can change in size). NOTE: This is why its important to change the “array_size” variable as stated in the file (yes, I know, I could have used malloc(), but I don’t quite understand how that works since I have very limited programming knowledge, and I didn’t feel like investing the time to figuring it out when this works).  Okay so now we have the buffer ready to go, we call the write() function, and bazinga, the drivers take care of everything else behind the scenes.

TODO: Like I said malloc() would be the best way to handle all different sizes of array instead of forcing the array to initialize with the largest array possible (usually the program data itself), but since I usually do embedded code I haven’t ever used malloc() before, so if you have time and would like to help better this code, please change it and let me know!

 

 

Now lets look at the 2nd core function, SIGMA_READ_REGISTER:

 

void SIGMA_READ_REGISTER(int devAddress, int address, int length, ADI_REG_TYPE * pData )
{
 
  int file;
  unsigned char dataAddr[2] = {0x00, 0x00};
  unsigned char deviceAddr = (devAddress>>1); //Address passed is the Write address, need to remove LSB in order to use this with ioctl
  struct i2c_rdwr_ioctl_data packets; //this is used to allow for the 2 byte register addresses
  struct i2c_msg messages[2]; // 2 transactions; 1st is the write to the register pointer, 2nd is the read
 
  dataAddr[0] = ((address>>8) & 0xFF); //grab the top 8 bits of the address
  dataAddr[1] = (address & 0xFF);  //grab the bottom 8 bits of the address
 
  deviceHandle = open("/dev/i2c-0", O_RDWR);
 
  if(deviceHandle == -1)
    printf("Open Failed!");
 
  messages[0].addr = deviceAddr; //the address of the DSP chip
  messages[0].len = 2; //2 Bytes register address
  messages[0].flags = 0; //no flags (default write operation)
  messages[0].buf = &dataAddr[0]; //the locatiion where the 2 element array containing the address is stored
 
  messages[1].addr = deviceAddr; //the address of the DSP chip
  messages[1].len = 4; //length
  messages[1].flags = I2C_M_RD; //read operation
  messages[1].buf = pData; //location where to store the info
 
  packets.nmsgs = 2; //total number of transactions
  packets.msgs = messages; 
 
  if (ioctl(deviceHandle,I2C_RDWR,&packets) < 0) //starts the transaction and checks for error in 1 step
  {
    printf("ioctl 2 Failed!\n");
    printf("Error no is : %d\n", errno);
    printf("Error description is : %s\n", strerror(errno));
    return;
  }
 
  close(file);
 
  return;
 
}

This function is quite a bit different than the write function. The raspberry pi SMBus drivers don’t support 2 Byte address on a read transaction, so we have to basically do the transaction the dirty way. It starts out the same with the device handle but then we see the messages structure. This is used in conjunction with the ioctl function. Doing the transaction this way allows us great control over what happens on the bus, which gives us the ability to do 2 Byte register addresses. I only have a little bit of understanding of how this way works (just enough to get the job done). I tried to comment what each step does. You fill out the messages structure, then you put that structure into the packets structure, which is the structure you send with the ioctl call. Stepping backwards the messages element zero is the address write transaction, followed by element 1 which is the read transaction. The length is set to 4 because I’ve only run into situations where the registers I am interested in are 4 bytes in size.

 

So that is it for the 2 core functions. The rest of the functions that I wrote just take the user input and convert it over to what the DSP wants, and vice versa. The “in a nutshell” explanation on this conversion can be explained here:

http://ez.analog.com/message/13377#13377

That is the information I used when creating these functions. The only problem I ran into was going from a user entered value that was in dB and converting it to the 4 Byte number the DSP wanted. I found that I still get rounding errors when using the code I wrote.

TODO: Fix the rounding errors when dealing with user values entered in dB or reading back a value and translating it to dB.

 

 

 

 

 

Leave a Reply

© 2014 - Brain Overload. All Rights Reserved. Powered by Wordpress and Design by We Create Web Designs