Important changes to forums and questions
All forums and questions are now archived. To start a new conversation or read the latest updates go to forums.mbed.com.
10 years, 6 months ago.
GCC for ARM Offline Toolchain won't Compile asm instructions
I am using the following library: https://developer.mbed.org/users/bridadan/code/WS2812/ and wanted to build it using the gcc for ARM compiler offline. When I run the makefile it throws an error saying "error: 'nop' was not declared in this scope".
I read that .s files are not exported for the offline compiler. However, it is necessary that I have the nop functionality working due to timing constraints. Could someone suggest how using assembly files can be achieved?
2 Answers
10 years, 6 months ago.
Hello,
I am getting errors that nop is not defined, as it's true for GCC ARM. It's valid for ARMCC http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0491c/CJABCDAD.html
If you replace those __nop() by __NOP(), then it compiles.
10 years, 6 months ago.
Hello,
I managed to hack together a solution for the K64F. I think it has something to do with optimization in the offline compiler. I took a scope to it and changed the iterations on constructor:
WS2812 ws(D9, WS2812_BUF, 0, 5, 5, 0);
I changed the 5's to different numbers, but nothing happened in the timing. If we take a look at the following function in WS2812.cpp:
void WS2812::write_offsets (int buf[],int r_offset, int g_offset, int b_offset)
I changed the variables "i" and "j" to be volatile, and this seemed to have some effect on the timing, but it took way to long.
Ultamately what I did, in the makefile for the library, change the optimization from "Os" to "O2", and the function I mentioned to:
hacked WS2812 solution
void WS2812::write_offsets (int buf[],int r_offset, int g_offset, int b_offset) {
    volatile int i;
    int totalSize = FRAME_SIZE * __size;
    
    // Load the transmit buffer
    __loadBuf(buf, r_offset, g_offset, b_offset);
    // Entering timing critical section, so disabling interrupts
    __disable_irq();
    
    // Begin bit-banging
    for (i = 0; i < totalSize; i++) {
        if (__transmitBuf[i]){
            __gpo = 1;
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __gpo = 0;
            __NOP();
            __NOP();
        } else {
            __gpo = 1;
            __NOP();
            __NOP();
            __gpo = 0;
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
        }
    }
    
    // Exiting timing critical section, so enabling interrutps
    __enable_irq();
}
The timing with the solution is not perfect (neither was the original really), but it works mostly. There is probably a better solution code wise. Ultimately, it is best to take out the scope and make sure the timing following the timing here.
Hope this helps someone.