| Customize Help

Setting and retrieving results from PU registers



Each PU has a dedicated register space which consists of three separate sections: a header section, an I/O control section, and a user-specific section. Each of these sections contains registers that hold specific information about the PU. Registers in the header and I/O sections do not require user modification, while registers in the user-specific section allow you to set the PU's operation settings. Most PUs that return non-image results also return these results in registers in the user-specific section.

You can set a PU's user-specific register section using up to four calls to MfpgaSetRegister(). Similarly, you can set up a request to retrieve the values of a PU's user-specific register section using up to four calls to MfpgaGetRegister(). Four calls is usually more than sufficient because you can write to or read from multiple registers at a single time.

For each PU, you are provided with PU-specific, predefined, C constructs to facilitate setting the PU's user-specific registers. The constructs are supplied in header files (fpga_*.h), located in the \Matrox Imaging\MIL\Examples\BoardSpecific\BoardName\BoardNameFDK\Include directory (for example, BoardNameFDK can be SoliosFDK). For custom PUs, use the generated register header files to write values to/read values from registers, instead of hardcoding a register or field offset, since these help keep your code forward-compatible.

In the header file, there is a structure that represents all the user-specific registers of the PU. For example, this is the structure for all the user-specific registers of the gainoffset PU.

/*************************************************************
* Section name  : USER
* USEROFF       : 0x60
**************************************************************/
typedef struct
{
  FPGA_GAINOFFSET_REG_CTRL    ctrl;    /* Address offset : [0x60] */
  FPGA_GAINOFFSET_REG_CLIPVAL clipval; /* Address offset : [0x68] */

} FPGA_GAINOFFSET_USER_ST;

In the header file, there is also a union for each user-specific register of the PU. Each union contains five items. The first four items u64, u32, u16, and u8 represent different sizes of data blocks that you can write to/read from the register. The last item is a C structure that facilitates setting and getting the different fields of the register. This union provides you with different ways of writing to/reading from the register. For example, you could clear all the fields of a register to 0 using the U64 item of the union. Alternatively, you could write specific values to the different register fields. The following is the union for the control (ctrl) register of the gainoffset PU.

/*************************************************************
* Register name : ctrl
* Address       : 0x60
**************************************************************/
typedef union
{
   MIL_UINT64 u64;
   MIL_UINT32 u32;
   MIL_UINT16 u16;
   MIL_UINT8  u8;

   struct
   {
      MIL_UINT64 dsttype              : 2;  /* Bits<1:0>,      */
             /* The data type and depth of the output image. */
      MIL_UINT64 gaintype             : 2;  /* Bits<3:2>,      */
             /* The data type and depth of the gain image.   */
      MIL_UINT64 offtype              : 2;  /* Bits<5:4>,      */
             /* The data type and depth of the offset image. */
      MIL_UINT64 srctype              : 2;  /* Bits<7:6>,      */
             /* The data depth and type of the input image on
             /* which to operate.                            */
      MIL_UINT64 shift                : 5;  /* Bits<12:8>,     */
             /* Number of bits to right-shift.               */
      MIL_UINT64 rsvd0                : 19; /* Bits<31:13>,    */
             /* Reserved Field                               */
   } f;

} FPGA_GAINOFFSET_REG_CTRL;

You should always set up and verify the values of the individual fields of each register before setting these values in the target PU. The following is an example that verifies the values for the registers of the gainoffset PU. If the wrong value is used, an error is returned.

/* Sets the gain offset registers */
/* Specifies the stream input port 0 data type. */
switch(Src1Type)
   {
   case 8+M_UNSIGNED:
      pGOShadow->ctrl.f.srctype = 0x1; break;
   case 16+M_UNSIGNED:
      pGOShadow->ctrl.f.srctype = 0x3; break;
   default:
      MosPrintf(MIL_TEXT("Gain offset error: Invalid input stream port 0 data type.\n"));
      break;
   }


/* Specifies the stream input port 1 data type. */
switch(Src2Type)
   {
   case 8+M_UNSIGNED:
      pGOShadow->ctrl.f.offtype = 0x1; break;
   case 16+M_UNSIGNED:
      pGOShadow->ctrl.f.offtype = 0x3; break;
   default:
      MosPrintf(MIL_TEXT("Gain offset  error: Invalid input stream port 1 data type.\n"));
      break;
   }

/* Specifies the stream input port 2 data type. */
switch(Src3Type)
   {
   case 8+M_UNSIGNED:
      pGOShadow->ctrl.f.gaintype = 0x1;   break;
   case 16+M_UNSIGNED:
      pGOShadow->ctrl.f.gaintype = 0x3;   break;
   default:
      MosPrintf(MIL_TEXT("Gain offset error: Invalid input stream port 3 data type.\n"));
      break;
   }

/* Specifies the stream output port 0 data type. */
switch(DstType)
   {
   case 8+M_UNSIGNED:
      pGOShadow->ctrl.f.dsttype = 0x1;   break;
   case 16+M_UNSIGNED:
      pGOShadow->ctrl.f.dsttype = 0x3;   break;
   default:
      MosPrintf(MIL_TEXT("Gain offset  error: Invalid output stream port 0 data type.\n"));
      break;
   }

/* Specifies the clipping value. */
pGOShadow->clipval.f.clipval  = lMaxValue;

/* Computes the number of bits to right-shift the output image. */
j=1;
for(i=0; i<32; i++)
   {
   if(Src4 & j)
      {
      pGOShadow->ctrl.f.shift = i;
      break;
      }
   j <<= 1;
   }

Once the values of the fields of all registers are set up, use MfpgaSetRegister() to specify the contents for your PU's registers. Note that when you queue your command with MfpgaCommandQueue(), the values set using MfpgaSetRegister() will be written to the hardware as a block once the hardware becomes free. For this reason, it is essential that you always set the values of all the fields of the target register before queueing the command.

/* Inquire the buffer info object for the source and destination buffers. */
MfuncInquire(MilSourceImage, M_BUFFER_INFO, &Src);
MfuncInquire(MilDestinationImage, M_BUFFER_INFO, &Dest);

/* Allocate an asynchronous command context on the AddConstant processing unit.
*/
if(MfpgaCommandAlloc(MfuncBufOwnerSystemId(Src), M_DEV0, FPGA_ADDCONST_FID,
                     M_DEFAULT,M_DEV0, M_ASYNCHRONOUS, M_DEFAULT,
                     &AddConstantContext))
  {
  /* Initialize the shadow register structure. */
  InitializeShadowRegisters(&ShadowRegisters, Src, ConstantValue, ControlFlag);

  /* Input0 of AddConstant processing unit is connected to the Src buffer. */
  MfpgaSetSource(AddConstantContext, Src, M_INPUT0, M_DEFAULT);

  /* Output0 of AddConstant processing unit is connected to the Dest buffer. */
  MfpgaSetDestination(AddConstantContext, Dest, M_OUTPUT0, M_DEFAULT);

  /* Pass the initialized shadow register structure, it will be programmed   */
  /* when the processing operation is dispatched (before processing starts). */
  MfpgaSetRegister(AddConstantContext, M_USER, 0, sizeof(ShadowRegisters),
                    (void*)(&ShadowRegisters), M_WHEN_DISPATCHED);

  /* Queue the processing operation, because this context is asynchronous, */
  /* MfpgaComamndQueue will return before the operation is completed. */
  MfpgaCommandQueue(AddConstantContext, M_DEFAULT, M_DEFAULT);

  /* Free the allocated context. */
  MfpgaCommandFree(AddConstantContext, M_DEFAULT);
  }