• 0
bitslip

PCAM5 PS_IIC.h SDK compilation error

Question

Hello,

While trying to compile (a modified version of) the 18.2 Zybo PCAM 5 demo inside the SDK I got the following error:

no matches converting function 'MyCallback' to type 'XIicPs_IntrHandler {aka void (*)(void*, long unsigned int)}'

The error pointed to the following line of code in a file named PS_IIC.h :

XIicPs_SetStatusHandler (&drv_inst_, &stat_handler_, &MyCallback<void(int)>);

Please explain this error.

Notes:

1. The Vivado project compiled correctly and the hardware was exported successfully to the SDK.

2. The PS_IIC.h file and a snapshot of the error message are attached.

snapshot.JPG

PS_IIC.h

Share this post


Link to post
Share on other sites

10 answers to this question

Recommended Posts

  • 0

Hi Ana-Maria,

10 days past since my last post - so I was beginning to loose hope...
Thanks for stepping in.

Quote

did you use the last version of the demo project from github?

Yes I did.

By "modified version" I mean that I changed the logic design in Vivado and re-exported the hardware to SDK.

When I tried to re-compile the C code inside SDK - I got many errors in various C and Header files. I managed to fix all - except of the one in this post.

Share this post


Link to post
Share on other sites
  • 0

It's a typo - the project IS defined as C++

I'd like to add that NO changes where made to the offending file named: PS_IIC.h

It's EXACTLY the same as in the original project.

Share this post


Link to post
Share on other sites
  • 0

I cannot reproduce your error in tag v2018.2-2 of the repo, so I am assuming it has something to do with your modifications.

PS_IIC.h is a header file, so the compilation error is actually coming from a module source (.cc) that includes it. The MyCallback shim function is a way to pass and a C++ class member function to a something (XIicPs_SetStatusHandler) that expects a function pointer of type XIicPs_IntrHandler.

For this to work you need the shim function to be of the type XIicPs_IntrHandler. Since

typedef void (*XIicPs_IntrHandler) (void *CallBackRef, u32 StatusEvent);

strictly speaking MyCallback should be of type (note the last argument type):

template <typename Func>
void MyCallback(void* CallbackRef, u32 i)

Try it and see if it works. For me, the function pointer type void (*)(void* CallbackRef, int i) is silently converted to XIicPs_IntrHandler.

Share this post


Link to post
Share on other sites
  • 0

I did something a little different.

I looked at AXI_VDMA.h file and change the contents of PS_IIC.h to be more like it.

This is what I did:

// I changed the original function prototype :

template <typename Func>
void MyCallback(void* CallbackRef, int i)
{
  auto pfn = static_cast<std::function<Func>*>(CallbackRef);
  pfn->operator()(i);
}

// To this :

template <typename Func>
void MyCallback(void* CallbackRef, uint32_t mask_or_type)
{
  auto pfn = static_cast<std::function<Func>*>(CallbackRef);
  pfn->operator()(mask_or_type);
}

////////////////////////////////////////////////////////////////////////////////////////////////////

// And I changed the original function call :

XIicPs_SetStatusHandler (&drv_inst_, &stat_handler_, &MyCallback<void(int)>);
     
// To this :     
        
XIicPs_SetStatusHandler (&drv_inst_, &stat_handler_, &MyCallback<void(uint32_t)>);

It now compiles well.

Can you explain why it didn't work and this solved it ?

Share this post


Link to post
Share on other sites
  • 0

You should not be modifying the template instantiation

&MyCallback<void(int)>

to

&MyCallback<void(uint32_t)>

, because it is incorrect, but it makes the other change actually work.

It is subtle, but bear with me. There is a bug in our code, which made the XIicPs_SetStatusHandler call actually use the MyCallback defined in the other header file, AXI_VDMA.h. This happens, because as I explained earlier, XIicPs_SetStatusHandler expects an argument of void (*)(void* CallbackRef, uint32_t i), which is defined in AXI_VDMA.h and not PS_IIC.h. C++ accepts function overloading for MyCallback and calls the one that fits the function prototype. In our project, PS_IIC.h was included after AXI_VDMA.h, so it found a fitting overload. It has the intended behavior but not the intended implementation.

So the correct implementation is to have the PS_IIC MyCallback have the same function prototype as the one XIicPs_SetStatusHandler is expecting, void (*) (void *CallBackRef, u32 StatusEvent). But since MyCallbacks are global functions, we get a re-definition error. I think the correct way to do this is to move the callback into the class as static member functions so there is no conflict.

Now, on to the other change. MyCallback is a template function executing a functor (std::function) that wraps a member function of an object. MyCallback has a C interface towards XIicPs_SetStatusHandler, and the functor makes the adaptation to the C++ member function. The functor is a member variable of the PS_IIC class under the name stat_handler_. Depending on the prototype of the member function you want to call, the std::function<> needs to be template instantiated with the right type. This type is the void(int) and is the type of void StatusHandler(int Event). This stat_handler_ is initialized in the ctor and bound to the member function it wraps. It is then passed to the XIicPs_SetStatusHandler as a void*. MyCallback casts this void* CallbackRef back to the std::function<> type and calls into it.

Phew, that was a lot. I will do a commit with the fix.

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now