AVR을 대상으로하는 C 코드가 있습니다. 이 코드는 기본적으로 올바른 백엔드가있는 gnu 컴파일러 인 avr-gcc로 컴파일됩니다.함수 포인터 위치가 전달되지 않습니다.
내가 뭘하려는 건 내 이벤트/인터럽트 구동 라이브러리 중 하나에서 콜백 메커니즘을 만드는 것입니다,하지만 난 몇 가지 문제가 함수 포인터의 가치를 유지하는 데있는 것 같습니다.
시작하려면 정적 라이브러리가 있어야합니다. 그것은 다음과 같습니다 헤더 파일 (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
// ...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_init
함수에서 twi->slave.slave_callback
에 할당 된 위치가 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
에있는 할당 이후에 fprintf
문을 제거하면 나중에 값을 다르게 읽는 문제가 발생했을 때 해결 방법을 생각해 냈습니다.
문제는 함수 포인터 주위를 지나가고있는 것 같습니다. 특히 포인터의 값 (함수 자체?)에 액세스하는 프로그램 부분은 기술적으로 다른 스레드에 있습니다.
아이디어가 있으십니까?
편집 : 코드에서
해결 오타. 실제 파일에
링크 : 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 라운드) : 나는 모든 최적화를 제거
- 예상대로, 내 "해결 방법"없이 코드가 작동합니다. 다시 -O를 추가하면 오류가 발생합니다. 왜 -O는 코드를 손상시키는 걸까요?
아마도 아무것도 바뀌지 않지만 main의 첫 번째 줄에서'&'를 제거해보십시오 :'twi_init (2, & bus_a, my_callback) ;; – pmg
몇 시간 동안 나가서 나중에 다시 시도하고 다시 시도해 보겠습니다. 해결되지 않은 경우 : 간단한 아이디어; 라이브러리를 사용하지 않으면 작동합니까? (즉, 모든 파일을 하나의 파일로 표시). 인터럽트에서 정말로 fprintf() 할 수 있습니까 (위험한 소리가 들림)? 모든 것을 보여주는 재 게시; 당신이 가진 것은 세부 사항에서 완벽하지 않습니다. 예를 들어, my_callback()의 길이 대 len과 같이, 인터럽트를 활성화하는 곳은 어디입니까? twi_driver.h 또는 twi_master_driver.h입니까? 아직 많이 도움이되지 않아서 미안해. 나중에 다시 시도 할거야. –
avr-gcc에 의해 생성 된 어셈블리는 회피 라인이있는 경우와없는 경우 어떻게 다릅니 까? 즉 두 버전 모두에 대해'avr-gcc -S twi_driver.c'의 결과를 게시 할 수 있습니까? 어떤 AVR을 타겟팅하고 있습니까? – mrkj