Note that there are some explanatory texts on larger screens.

plurals
  1. POFunction pointer location not getting passed
    text
    copied!<p>I've got some C code I'm targeting for an AVR. The code is being compiled with avr-gcc, basically the gnu compiler with the right backend.</p> <p>What I'm trying to do is create a callback mechanism in one of my event/interrupt driven libraries, but I seem to be having some trouble keeping the value of the function pointer.</p> <p>To start, I have a static library. It has a header file (<code>twi_master_driver.h</code>) that looks like this:</p> <pre><code>#ifndef TWI_MASTER_DRIVER_H_ #define TWI_MASTER_DRIVER_H_ #define TWI_INPUT_QUEUE_SIZE 256 // define callback function pointer signature typedef void (*twi_slave_callback_t)(uint8_t*, uint16_t); typedef struct { uint8_t buffer[TWI_INPUT_QUEUE_SIZE]; volatile uint16_t length; // currently used bytes in the buffer twi_slave_callback_t slave_callback; } twi_global_slave_t; typedef struct { uint8_t slave_address; volatile twi_global_slave_t slave; } twi_global_t; void twi_init(uint8_t slave_address, twi_global_t *twi, twi_slave_callback_t slave_callback); #endif </code></pre> <p>Now the C file (<code>twi_driver.c</code>):</p> <pre><code>#include &lt;stdint.h&gt; #include "twi_master_driver.h" void twi_init(uint8_t slave_address, twi_global_t *twi, twi_slave_callback_t slave_callback) { twi-&gt;slave.length = 0; twi-&gt;slave.slave_callback = slave_callback; twi-&gt;slave_address = slave_address; // temporary workaround &lt;- why does this work?? twi-&gt;slave.slave_callback = twi-&gt;slave.slave_callback; } void twi_slave_interrupt_handler(twi_global_t *twi) { (twi-&gt;slave.slave_callback)(twi-&gt;slave.buffer, twi-&gt;slave.length); // some other stuff (nothing touches twi-&gt;slave.slave_callback) } </code></pre> <p>Then I build those two files into a static library (.a) and construct my main program (<code>main.c</code>) #include #include #include #include #include "twi_master_driver.h"</p> <pre><code>// ...define microcontroller safe way for mystdout ... twi_global_t bus_a; ISR(TWIC_TWIS_vect, ISR_NOBLOCK) { twi_slave_interrupt_handler(&amp;bus_a); } void my_callback(uint8_t *buf, uint16_t len) { uint8_t i; fprintf(&amp;mystdout, "C: "); for(i = 0; i &lt; length; i++) { fprintf(&amp;mystdout, "%d,", buf[i]); } fprintf(&amp;mystdout, "\n"); } int main(int argc, char **argv) { twi_init(2, &amp;bus_a, &amp;my_callback); // ...PMIC setup... // enable interrupts. sei(); // (code that causes interrupt to fire) // spin while the rest of the application runs... while(1){ _delay_ms(1000); } return 0; } </code></pre> <p>I carefully trigger the events that cause the interrupt to fire and call the appropriate handler. Using some fprintfs I'm able to tell that the location assigned to <code>twi-&gt;slave.slave_callback</code> in the <code>twi_init</code> function is different than the one in the <code>twi_slave_interrupt_handler</code> function.</p> <p>Though the numbers are meaningless, in <code>twi_init</code> the value is 0x13b, and in <code>twi_slave_interrupt_handler</code> when printed the value is 0x100.</p> <p>By adding the commented workaround line in <code>twi_driver.c</code>:</p> <pre><code>twi-&gt;slave.slave_callback = twi-&gt;slave.slave_callback; </code></pre> <p>The problem goes away, but this is clearly a magic and undesirable solution. What am I doing wrong?</p> <p>As far as I can tell, I've marked appropriate variables <code>volatile</code>, and I've tried marking other portions volatile and removing the volatile markings. I came up with the workaround when I noticed removing <code>fprintf</code> statements after the assignment in <code>twi_init</code> caused the value to be read differently later on.</p> <p>The problem seems to be with how I'm passing around the function pointer -- and notably the portion of the program that is accessing the value of the pointer (the function itself?) is technically in a different thread.</p> <p>Any ideas?</p> <p>Edits:</p> <ul> <li><p>resolved typos in code.</p></li> <li><p>links to actual files: <a href="http://straymark.com/code/" rel="nofollow noreferrer">http://straymark.com/code/</a> [test.c|twi_driver.c|twi_driver.h]</p></li> <li><p>fwiw: compiler options: <code>-Wall -Os -fpack-struct -fshort-enums -funsigned-char -funsigned-bitfields -mmcu=atxmega128a1 -DF_CPU=2000000UL</code></p></li> <li><p>I've tried the same code included directly (rather than via a library) and I've got the same issue.</p></li> </ul> <p>Edits (round 2):</p> <ul> <li>I removed all the optimizations, without my "workaround" the code works as expected. Adding back -Os causes an error. Why is -Os corrupting my code?</li> </ul>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload