У меня есть код C, на который я нацелен для AVR. Код компилируется с помощью avr-gcc, в основном компилятор gnu с правом бэкэнда.Не удалось получить местоположение указателя функции
То, что я пытаюсь сделать, это создать механизм обратного вызова в одной из моих управляемых событиями/прерываниями библиотек, но, похоже, у меня проблемы с сохранением значения указателя функции.
Для начала у меня есть статическая библиотека. Он имеет заголовочный файл (twi_master_driver.h
), который выглядит следующим образом:
#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
Теперь файл C (twi_driver.c
):
#include <stdint.h>
#include "twi_master_driver.h"
void twi_init(uint8_t slave_address, twi_global_t *twi, twi_slave_callback_t slave_callback)
{
twi->slave.length = 0;
twi->slave.slave_callback = slave_callback;
twi->slave_address = slave_address;
// temporary workaround <- why does this work??
twi->slave.slave_callback = twi->slave.slave_callback;
}
void twi_slave_interrupt_handler(twi_global_t *twi)
{
(twi->slave.slave_callback)(twi->slave.buffer, twi->slave.length);
// some other stuff (nothing touches twi->slave.slave_callback)
}
Затем создадим эти два файла в статическую библиотеку (.a) и построить свою основную программу (main.c
) #include #include #include #include #include "twi_master_driver.h"
// ...define microcontroller safe way for mystdout ...
twi_global_t bus_a;
ISR(TWIC_TWIS_vect, ISR_NOBLOCK)
{
twi_slave_interrupt_handler(&bus_a);
}
void my_callback(uint8_t *buf, uint16_t len)
{
uint8_t i;
fprintf(&mystdout, "C: ");
for(i = 0; i < length; i++)
{
fprintf(&mystdout, "%d,", buf[i]);
}
fprintf(&mystdout, "\n");
}
int main(int argc, char **argv)
{
twi_init(2, &bus_a, &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;
}
Я тщательно провожу события, вызывающие прерывание, и вызывает соответствующий обработчик. Используя некоторые fprintfs, я могу сказать, что местоположение, назначенное twi->slave.slave_callback
в функции twi_init
, отличается от функции в функции twi_slave_interrupt_handler
.
Хотя цифры не имеют смысла, в twi_init
значение равно 0x13b, а в twi_slave_interrupt_handler
при печати значение равно 0x100.
Добавляя комментируемой обходной линии в twi_driver.c
:
twi->slave.slave_callback = twi->slave.slave_callback;
Проблема уходит, но это явно магическое и нежелательное решение. Что я делаю не так?
Насколько я могу судить, я отметил соответствующие переменные volatile
, и я пробовал маркировать другие порции летучих и удалять летучие маркировки. Я придумал обходной путь, когда заметил, что после вывода twi_init
операторы заставили считывать значение по-разному.
Проблема заключается в том, как я прохожу через указатель на функцию - и особенно часть программы, которая обращается к значению указателя (самой функции?), Технически находится в другом потоке.
Любые идеи?
изменение:
разрешенных опечатки в коде.
ссылки на реальные файлы: http://straymark.com/code/ [test.c | twi_driver.c | twi_driver.h]
FWIW: опции компилятора:
-Wall -Os -fpack-struct -fshort-enums -funsigned-char -funsigned-bitfields -mmcu=atxmega128a1 -DF_CPU=2000000UL
я пробовал тот же код включен непосредственно (а не через библиотеку), и у меня такая же проблема.
редактирует (круглые 2):
- Я удалил все оптимизации, без моего "обходного" код работает, как ожидалось. Добавление back -Os вызывает ошибку. Почему -O развращает мой код?
Возможно, ничего не изменилось, но попробуйте удалить '&' из первой строки в main: 'twi_init (2, & bus_a, my_callback);' – pmg
Выйти в течение нескольких часов, но я проверю позже и повторю попытку если не решена: Краткие идеи; Это работает, если вы не используете библиотеку? (т. е. все отображаемое в одном файле). Можете ли вы действительно fprintf() от прерывания (звучит опасно) ?. Репост показывает все; Что вы имеете, не совсем совершенны в деталях, например length vs len в my_callback(), где вы разрешаете прерывания? это twi_driver.h или twi_master_driver.h? Извините, что не очень помог, так как я говорю, что попробую позже. –
Как сборка, сгенерированная avr-gcc, отличается и без обходной линии? т. е. вы могли бы опубликовать результаты 'avr-gcc -S twi_driver.c' для обеих версий? На какие AVR вы нацеливаетесь? – mrkj