Callback function - Can't generate code for this expression

Discussion in 'Embedded Systems and Microcontrollers' started by spinnaker, Feb 25, 2014.

  1. spinnaker

    Thread Starter AAC Fanatic!

    Oct 29, 2009
    Not sure if this belongs in the Programmers Corner or here. But since it is the XC8 compiler I figured I would put it here.

    I am getting a Can't generate code for this expression in the following code:

    Code ( (Unknown Language)):
    2. typedef  void (*OW_update_cb)(unsigned int count);
    4. void foo(OW_update_cb update_cb)
    5. {
    7.      update_cb(0);  // Error occurs here
    8. }
    If I make my return type an int then everything compiles OK. Or if I do not have any parameters and a void return type for the callback function then it compiles.

    This compiles with the corresponding correction to the call to the callback.
    typedef void (*OW_update_cb)();

    This also compiles just fine.
    typedef int (*OW_update_cb)(unsigned int count);

    Any idea what is going on? I have not used callback functions all that much.
  2. JohnInTX


    Jun 26, 2012
    That's the way I've done it (in HiTech C) as well. But I moved the '*' outside the parenthesis
    Code ( (Unknown Language)):
    1. typedef void *(OW_update_cb) (unsigned int count);
    and it compiles. Don't know if it generates the code you want.

    Good luck.

    EDIT XC8 1.21 FREE mode
  3. spinnaker

    Thread Starter AAC Fanatic!

    Oct 29, 2009

    This worked for some reason.
    typedef void *(OW_update_cb)(unsigned int count);

    The only thing, the editor complains "Unable to resolve identifier count" but it compiles.

    I'll test tomorrow to see if the code actually works. Time for bed now. :)

    This is the last project I am going to be doing in XC8 for a while. I am switching back to MPLab. I never had more trouble with a compiler, all kind of issues.
  4. JohnInTX


    Jun 26, 2012
    It should work as you wrote it. Here's a little gem from XC8 Compiler Help:
    Boldface added.

    EDIT It didn't seem to generate ANY code for the callback fragment you posted, even when changing the type to int(*) without calling 'foo'. When 'foo' is called, it looks like it correctly pushes the address contained in the pointer-to-function variable update_cb on the stack and do a 'return' to call the function. It also accepted the original typedef syntax.

    Yeah.. kind of agree with you there. I keep trying it for various things and run across this kind of stuff as well.

    If you think its a compiler issue, send a gripe to Microchip support. They may have a workaround or at least put it on the 'issues' list.

    This generates code and gets to 'bar':
    Code ( (Unknown Language)):
    1. #include <xc.h>
    2. typedef  void(*OW_update_cb)(unsigned int);
    4. void bar(){
    5.     unsigned char i;
    6.     for(i=0;i<10;i++); // give it something to do so it doesn't get optimised out
    7. }
    9. void foo(OW_update_cb update_cb)
    10. {
    11.     update_cb(0);  // Error occurs here
    12. }
    14. void main()
    15. {
    16.    while (1){
    17.       foo((OW_update_cb)bar);
    18.    }
    19. }
    Here's the generated code:
    Code ( (Unknown Language)):
    1.             #include <xc.h>
    2. 9:             typedef  void(*OW_update_cb)(unsigned int);
    3. 10:            
    4. 11:            void bar(){
    5. 12:                unsigned char i;
    6. 13:                for(i=0;i<10;i++); // give it something to do so it doesn't get optimised out
    7. 7FCA  6E03     MOVWF 0x3, ACCESS
    8. 7FCC  0E00     MOVLW 0x0
    9. 7FCE  6E04     MOVWF i, ACCESS
    10. 7FD0  5003     MOVF 0x3, W, ACCESS
    11. 7FD2  D001     BRA 0x7FD6
    12. 7FD4  2A04     INCF i, F, ACCESS
    13. 7FD6  0E09     MOVLW 0x9
    14. 7FD8  6404     CPFSGT i, ACCESS
    15. 7FDA  D7FC     BRA 0x7FD4
    16. 14:            }
    17. 7FDC  0012     RETURN 0
    18. 15:            
    19. 16:            void foo(OW_update_cb update_cb)
    20. 17:            {
    21. 18:                update_cb(0);  // Error occurs here
    22. [I];;Put 0 param into registers[/I] 01h,02h
    23. 7FDE  0E00     MOVLW 0x0
    24. 7FE0  6E02     MOVWF 0x2, ACCESS
    25. 7FE2  0E00     MOVLW 0x0
    26. 7FE4  6E01     MOVWF 0x1, ACCESS
    27. 7FE6  D801     RCALL 0x7FEA
    28. 7FE8  D00A     BRA 0x7FFE
    29. [I];; Push stack, put contents of update_cb (&bar) on TOPSTK[/I]
    30. 7FEA  0005     PUSH
    32. 7FEE  5005     MOVF update_cb, W, ACCESS
    33. 7FF0  6EFD     MOVWF TOSL, ACCESS
    34. 7FF2  5006     MOVF 0x6, W, ACCESS
    35. 7FF4  6EFE     MOVWF TOSH, ACCESS
    36. 7FF6  50F8     MOVF TBLPTRU, W, ACCESS
    37. 7FF8  6EFF     MOVWF TOSU, ACCESS
    38. 7FFA  50FA     MOVF PCLATH, W, ACCESS
    39. [I];; POP address of 'bar' into PC to call it[/I]
    40. 7FFC  0012     RETURN 0
    41. 19:            }
    42. 20:            
    43. 21:            void main()
    44. 22:            {
    45. 23:               while (1){
    46. 24:                  foo((OW_update_cb)bar);
    47. ;; [I]This puts the address of 'bar' (7FCA) into update_cb[/I]
    48. 7FBC  0E7F     MOVLW 0x7F  
    49. 7FBE  6E06     MOVWF 0x6, ACCESS
    50. 7FC0  0ECA     MOVLW 0xCA
    51. 7FC2  6E05     MOVWF update_cb, ACCESS
    52. 7FC4  ECEF     CALL 0x7FDE, 0
    53. 7FC6  F03F     NOP
    54. 7FC8  D7F9     BRA main
    55. 25:               }
    56. 26:            }
    Last EDIT - bed for me as well :)
    That's common and I don't know why it is exactly. It will also flag some library functions/macros delay macros as unresolved but they compile correctly as well. Its still pretty handy to the extent that it does work.
    Last edited: Feb 26, 2014
  5. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    But what compiler will you be using inside MPLAB?
  6. spinnaker

    Thread Starter AAC Fanatic!

    Oct 29, 2009
  7. nsaspook

    AAC Fanatic!

    Aug 27, 2009
    Still waiting for XC8 to be a good bare-metal compiler in 'lite mode' but upgrade to 1.30 to see if that helps. C18 might be slow and simple but it usually generates usable (lacking optimization but not artificially bloated) code in the LITE mode and can still be used in MPLABX if you change the project compiler setting.

    My first opinion of XC8 hasn't change much over the years.
    Last edited: Feb 26, 2014