New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ESP32 corrupted data within rmt device #719

Open
Crejan opened this Issue Jan 18, 2019 · 6 comments

Comments

Projects
None yet
2 participants
@Crejan
Copy link

Crejan commented Jan 18, 2019

Hi
i have a problem with my ESP32 controlled WS2812 LEDS. As long as I do not use Bluetooth or WiFi everything is fine. But after enabling Bluetooth or connecting WiFi to an existing network (AP seems to work fine) Strange things begin to happen in the RMT subsystem.

The problem is a color flickering starting from one (random) LED in the stripe and affecting all following ones appearing about once or twice a second.

First I thought that the problem is due to interruptions by the WiFi or Bluetooth communication but nothing so I tried the following:

  • Disable Interrupts: FASTLED_ALLOW_INTERRUPTS 0
  • Only using one RMT channel: FASTLED_RMT_MAX_CHANNELS 1
  • Remove every other thread from Core 1 (by modifying freeRTOS) xTaskCreatePinnedToCore and xTaskCreate

Nothing helped. So I tried to diagnose the problem by only sending static data to the LEDS and connecting an Oscilloscope to the data channel so every frame should look the same:
The first result was that the "bad" frames are a little bit longer than expected. and the content was different too. So it is no issue of the LEDs itself. I expected to see the frame tear appart at some point because of an interrupt disturbing the software during RMT buffer fillup but that was not the case. In fact the data itself seems to be corrupted. I achieved to get an image of a frame that was damaged it the very beginning so it was easy to compare it to a valid frame and found out that after byte 8 things start to get strange.
The expected datastream whoul be repeatingly: 00000101 00001100 00000000

 Index:     6        7        8        9       10       11        12 
Target: 00000101 00001100 00000000 00000101 00001100 00000000 00000101 
Actual: 00000101 00001100 00000101 00001100 00000000 00000101 00001100 
 Index:    OK      OK      NOK      NOK        8        9        10 

So somehow there get 16 byte inserted into the bitstream after byte index 7 this not only destroys the one pixel but shifts the whole stream and creates wrong colors.


You can find the Image and csv data from the oscilloscope here:

I also tried to replace the rmt code of esp by a very simplified code which causes the same issues.

int cur = 0;
        while (pixels.has(1)) {
            uint8_t byte = 0x04;
            //uint8_t byte = pixels.loadAndScale0();
            led_data[cur++] = byte & 0x80 ? mOne : mZero;
            led_data[cur++] = byte & 0x40 ? mOne : mZero;
            led_data[cur++] = byte & 0x20 ? mOne : mZero;
            led_data[cur++] = byte & 0x10 ? mOne : mZero;
            led_data[cur++] = byte & 0x08 ? mOne : mZero;
            led_data[cur++] = byte & 0x04 ? mOne : mZero;
            led_data[cur++] = byte & 0x02 ? mOne : mZero;
            led_data[cur++] = byte & 0x01 ? mOne : mZero;
            //byte = pixels.loadAndScale1();
            led_data[cur++] = byte & 0x80 ? mOne : mZero;
            led_data[cur++] = byte & 0x40 ? mOne : mZero;
            led_data[cur++] = byte & 0x20 ? mOne : mZero;
            led_data[cur++] = byte & 0x10 ? mOne : mZero;
            led_data[cur++] = byte & 0x08 ? mOne : mZero;
            led_data[cur++] = byte & 0x04 ? mOne : mZero;
            led_data[cur++] = byte & 0x02 ? mOne : mZero;
            led_data[cur++] = byte & 0x01 ? mOne : mZero;
            //byte = pixels.loadAndScale2();
            led_data[cur++] = byte & 0x80 ? mOne : mZero;
            led_data[cur++] = byte & 0x40 ? mOne : mZero;
            led_data[cur++] = byte & 0x20 ? mOne : mZero;
            led_data[cur++] = byte & 0x10 ? mOne : mZero;
            led_data[cur++] = byte & 0x08 ? mOne : mZero;
            led_data[cur++] = byte & 0x04 ? mOne : mZero;
            led_data[cur++] = byte & 0x02 ? mOne : mZero;
            led_data[cur++] = byte & 0x01 ? mOne : mZero;
            pixels.advanceData();
            pixels.stepDithering();
        }
        led_data[cur++] = mReset;

        rmtWrite(rmt_send, led_data, cur);

I am out of ideas how to solve this.I hope anyone here can help me?

Best regards
Jan

@focalintent

This comment has been minimized.

Copy link
Member

focalintent commented Jan 18, 2019

The drive url you gave doesn’t work.

Also while it appears to be either an extra 16 bits was inserted - alternatively, it could be a byte was dropped - you’re sending the same 3 bytes repeatedly, so both things happening would look the same.

@samguyer - thoughts?

@focalintent

This comment has been minimized.

Copy link
Member

focalintent commented Jan 18, 2019

Does putting

#define FASTLED_RMT_BUILTIN_DRIVER 1

Before you include FastLED help? I have a theory about what’s going on that I can expand on later when not typing on a phone.

@Crejan

This comment has been minimized.

Copy link
Author

Crejan commented Jan 19, 2019

Then the system crashes right away. I tried this too before all of my modifications but if I remember right the system crashed immediately with this option.

@Crejan

This comment has been minimized.

Copy link
Author

Crejan commented Jan 19, 2019

I updated the link in the post above. I am sure that bytes get inserted, because the total signal for one frame is longer too in the error case.

@focalintent

This comment has been minimized.

Copy link
Member

focalintent commented Jan 19, 2019

Ok - I think what might be happening is the interrupt to refill the rmt buffer may be getting handled too late - causing a chunk of data to get written out again. @samguyer - do you know why the rmt builtin driver was crashing? Also the rest of the code appears to assume that the interrupt will be handled and doesn’t appear to have any checks to verify that it was.

@Crejan

This comment has been minimized.

Copy link
Author

Crejan commented Jan 21, 2019

I changed the code of the clockless_esp32.h to use SPI for the signal generation:


template<int DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 5>
class ClocklessController : public CPixelLEDController<RGB_ORDER> {

    SPIClass * hspi = nullptr;
    uint8_t *led_data = nullptr;
    // H:875 L:375
    static const uint8_t mOne = 0xf8;
    // H:250 L:1000
    static const uint8_t mZero = 0x80;
    int mSize = 0;

public:

    void init() {
        hspi = new SPIClass(HSPI);
        hspi->begin();
    }

    virtual uint16_t getMaxRefreshRate() const {
        return 400;
    }

protected:

    virtual void showPixels(PixelController<RGB_ORDER> &pixels) { ;
        const int RESET_LENGTH = 10;
        int size_needed = pixels.size() * 3 * 8  + RESET_LENGTH;
        if (size_needed != mSize) {
            if (led_data != nullptr)
                free(led_data);
            mSize = size_needed;
            led_data = (uint8_t*) malloc(mSize * sizeof(rmt_data_t));
            for(int i=size_needed-RESET_LENGTH; i<size_needed; ++i){
                led_data[i] = 0;
            }
        }

        int cur = 0;
        while (pixels.has(1)) {
            uint8_t byte = pixels.loadAndScale0();
            led_data[cur++] = byte & 0x80 ? mOne : mZero;
            led_data[cur++] = byte & 0x40 ? mOne : mZero;
            led_data[cur++] = byte & 0x20 ? mOne : mZero;
            led_data[cur++] = byte & 0x10 ? mOne : mZero;
            led_data[cur++] = byte & 0x08 ? mOne : mZero;
            led_data[cur++] = byte & 0x04 ? mOne : mZero;
            led_data[cur++] = byte & 0x02 ? mOne : mZero;
            led_data[cur++] = byte & 0x01 ? mOne : mZero;
            byte = pixels.loadAndScale1();
            led_data[cur++] = byte & 0x80 ? mOne : mZero;
            led_data[cur++] = byte & 0x40 ? mOne : mZero;
            led_data[cur++] = byte & 0x20 ? mOne : mZero;
            led_data[cur++] = byte & 0x10 ? mOne : mZero;
            led_data[cur++] = byte & 0x08 ? mOne : mZero;
            led_data[cur++] = byte & 0x04 ? mOne : mZero;
            led_data[cur++] = byte & 0x02 ? mOne : mZero;
            led_data[cur++] = byte & 0x01 ? mOne : mZero;
            byte = pixels.loadAndScale2();
            led_data[cur++] = byte & 0x80 ? mOne : mZero;
            led_data[cur++] = byte & 0x40 ? mOne : mZero;
            led_data[cur++] = byte & 0x20 ? mOne : mZero;
            led_data[cur++] = byte & 0x10 ? mOne : mZero;
            led_data[cur++] = byte & 0x08 ? mOne : mZero;
            led_data[cur++] = byte & 0x04 ? mOne : mZero;
            led_data[cur++] = byte & 0x02 ? mOne : mZero;
            led_data[cur++] = byte & 0x01 ? mOne : mZero;
            pixels.advanceData();
            pixels.stepDithering();
        }
        const SPISettings settings(6400000, MSBFIRST, SPI_MODE0);
        hspi->beginTransaction(settings);
        hspi->writeBytes(led_data, cur);
        hspi->endTransaction();
    }

};

This solves the problem for me. But I still think, that there is a bug inside the RMT code somewhere

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment