2014-12-22 2 views
0

이것은 AVR (Arduino 하드웨어) 용 WS2812B RGB LED 스트립 드라이브 코드입니다. 내 코드의 일부를 최적화하는 컴파일러에 몇 가지 문제가 있습니다. -O1, -O2, -Os, 동일한 결과를 보았습니다. 지연이 작동하지 않기 때문에 -O0을 사용할 수 없습니다.상수 값을 사용할 때 매크로 부분이 최적화 됨

매크로

다음

ws_driverm.h 파일입니다

#pragma once  
#include <util/delay_basic.h> 
#include <avr/io.h>  
#include "lib/pins.h" 

#define WS_T_1H 800 
#define WS_T_1L 450 
#define WS_T_0H 200 
#define WS_T_0L 850 
#define WS_T_LATCH 7000 

/** Latch and display the RGB values */ 
#define ws_show(io) do { pin_low(io_pack(io)); delay_ns_c(WS_T_LATCH, 0); } while(0) 

/** Send one byte to the RGB strip */ 
#define ws_send_byte(io, bb) do {        \ 
    for (int8_t __wsba_i = 7; __wsba_i >= 0; --__wsba_i) {  \ 
     if (bb & (1 << __wsba_i)) {        \ 
      pin_high(io_pack(io)); delay_ns_c(WS_T_1H, -2);  \ 
      pin_low(io_pack(io)); delay_ns_c(WS_T_1L, -10);  \ 
     } else {            \ 
      pin_high(io_pack(io)); delay_ns_c(WS_T_0H, -2);  \ 
      pin_low(io_pack(io)); delay_ns_c(WS_T_0L, -10);  \ 
     }              \ 
    }               \ 
} while(0) 

/** Send RGB color to the strip */ 
#define ws_send_rgb(io, r, g, b) do {   \ 
    ws_send_byte(io_pack(io), g);    \ 
    ws_send_byte(io_pack(io), r);    \ 
    ws_send_byte(io_pack(io), b);    \ 
} while(0) 

실패 나는 그것이 매크로 것에 대해 행복하지 않다,하지만 내 모든 시도 등의 IO 포트, 포트 주소로 포인터를 사용 할 수 있습니다.

io은 내 핀 처리 시스템의 일부이며, 무시해도됩니다. 질문과 관련이 없습니다.

문제 여기

는 예상대로 작동, 내가 변경, 또는 휘발성을 표시하기 위해 보장 변수를 사용하는 경우 (주 단위) 문제

입니다 :

volatile uint8_t r = 0; 
volatile uint8_t g = 255; 
volatile uint8_t b = 0; 
ws_send_rgb(PIN_WS, r, g, b); 
ws_show(PIN_WS); 
// results in GREEN color 

변수가 휘발성이 아니거나 숫자를 매크로 호출에 넣으면 작동하지 않습니다.

uint8_t r = 0; 
uint8_t g = 255; 
uint8_t b = 0; 
ws_send_rgb(PIN_WS, r, g, b); 
ws_show(PIN_WS); 
// results in YELLOW color 

같은 결과 : 그것은 일정 제로의 경우

ws_send_rgb(PIN_WS, 0, 255, 0); 
ws_show(PIN_WS); 
// results in YELLOW color 

분명히 매크로에 의해 생성 된 코드가 어떤 이유로, 멀리 최적화되어 (적어도 그렇게 보이는 - 나는 이유는 정말 모르겠어요 LED가 노란색으로 표시됨).

재미있는 : ->0 대신 1을 사용하면 예상대로 작동합니다.

내 매크로에 어떤 문제가 있으며 어떻게 해결할 수 있습니까? 더러운 해결 방법은 현재까지 유효합니다.

+0

'PIN_WS'정의 란 무엇이며 'pin_low','iopack' 및 'delay_ns_c' 정의 방법은 무엇입니까? – ouah

+0

그들은 몇 가지 매크로를 속임수로 사용하고 있습니다. 여기에 전체 pins.h 파일을 붙여 넣는 것이 좋은지 잘 모르겠습니다. 기본적으로 IO 포트 (PORTB)에 비트를 씁니다. 본질적으로,'pin_high (PIN_WS)'는'do {((휘발성) uint8_t * ((0x05) + 0x20)))} = = (1 << 0); } while (0);'전처리기에 의해 씹어 먹은 후. 아니면, 인간이 읽을 수있는,'PORTB | = (1 << 0); – MightyPork

+0

그것은 실패한 코드의 어셈블러리스트를 보는 것이 드러날 것이다. – Armali

답변

0

나는 pin_highpin_low이 (가) 메모리 주소에 쓰고 있습니다. 무슨 일

컴파일러는 다음과 같이 코드를 부여하고 있습니다 (효과)입니다 : 일반 메모리에

char *address = ...; 
*address = something; 
*address = somethingelse; 

그것은이 두 번째 줄을 삭제 것 때문에 address 경우 점, 다음이 아무 작업도 수행하지 않습니다. 그러나 그렇지 않습니다. 기억에 대한 쓰기는 중요한 부작용이 있습니다.

이렇게하려면 pin_highpin_lowmemory barrier 또는 그와 비슷한 것으로 수정해야합니다. 그러나 volatile 키워드로 수정됩니다. 나는 메모리 주소 (또는 그 내용)가 실제로 쓰여지는 것보다 volatile이되어야하기 때문에 우연히 해결할 수 있다고 생각한다.

여기서 가능한 경로는 메모리 장벽으로 작용하는 아무 것도 희망하지 않는 C 함수를 도입하는 것입니다.컴파일러의 것들이 쓰여진 값을 사용할 수도 있습니다). 이것을 최적화하지 말아야합니다. 예를 들어 : 매크로에서 다음

static void donothingroutine() {} 
volatile void (*donothing)() = &donothingroutine; 

는 추가 :

donothing(); 

volatile를 선언 루틴에 대한 포인터로보기 donothing()의 컴파일러의 입장에서이 에 액세스하는 루틴 수 있습니다 '메모리'가 쓰여지므로 쓰기를 최적화 할 수 없습니다. 그래서 매크로 안에 자유롭게 뿌리십시오.

+0

작동하지 않았다. 핀에 대한 두 번의 쓰기 사이에'donothingroutine(); '을 추가했다. 기록 된 메모리 위치는 휘발성이며 avr-libc는이를 처리합니다. '((휘발성 uint8_t *) ((0x05) + 0x20))) | = (1 << 0)' – MightyPork

+0

오! 나는 해결책을 발견했다 - 그러나 아마 최고가 아니다. 휘발성 매크로에서 루프 변수를 만들면 잘 작동합니다. 그게 올바른 해결책으로 보이나요? – MightyPork

+0

당신이 컴파일러의 휴리스틱에 의존하고 있다고 생각합니다. 지금 당장은 효과가 있지만 현재로서는 적절한 메모리 장벽이 필요할 것입니다. – abligh

1

저는이 방법으로 지금까지 풀었습니다. - 꽤 잘 작동합니다 : 루프 변수에 volatile 키워드를 추가했습니다.

왜 도움이되었는지는 모르지만 그랬습니다.

/** Send one byte to the RGB strip */ 
#define ws_send_byte(io, bb) do {        \ 
    for (volatile int8_t __wsba_i = 7; __wsba_i >= 0; --__wsba_i) {  \ 
     if (bb & (1 << __wsba_i)) {        \ 
      pin_high(io_pack(io)); delay_ns_c(WS_T_1H, -2);  \ 
      pin_low(io_pack(io)); delay_ns_c(WS_T_1L, -10);  \ 
     } else {            \ 
      pin_high(io_pack(io)); delay_ns_c(WS_T_0H, -2);  \ 
      pin_low(io_pack(io)); delay_ns_c(WS_T_0L, -10);  \ 
     }              \ 
    }               \ 
} while(0) 
관련 문제