{"action":"created","issue":{"url":"https://api.github.com/repos/adafruit/Adafruit_NeoPixel/issues/139","repository_url":"https://api.github.com/repos/adafruit/Adafruit_NeoPixel","labels_url":"https://api.github.com/repos/adafruit/Adafruit_NeoPixel/issues/139/labels{/name}","comments_url":"https://api.github.com/repos/adafruit/Adafruit_NeoPixel/issues/139/comments","events_url":"https://api.github.com/repos/adafruit/Adafruit_NeoPixel/issues/139/events","html_url":"https://github.com/adafruit/Adafruit_NeoPixel/issues/139","id":228912144,"number":139,"title":"ESP32: timing error every 1ms corrupts LED pixel data","user":{"login":"MustBeArt","id":5356541,"avatar_url":"https://avatars3.githubusercontent.com/u/5356541?v=4","gravatar_id":"","url":"https://api.github.com/users/MustBeArt","html_url":"https://github.com/MustBeArt","followers_url":"https://api.github.com/users/MustBeArt/followers","following_url":"https://api.github.com/users/MustBeArt/following{/other_user}","gists_url":"https://api.github.com/users/MustBeArt/gists{/gist_id}","starred_url":"https://api.github.com/users/MustBeArt/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/MustBeArt/subscriptions","organizations_url":"https://api.github.com/users/MustBeArt/orgs","repos_url":"https://api.github.com/users/MustBeArt/repos","events_url":"https://api.github.com/users/MustBeArt/events{/privacy}","received_events_url":"https://api.github.com/users/MustBeArt/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":18,"created_at":"2017-05-16T04:27:33Z","updated_at":"2018-04-10T10:46:58Z","closed_at":null,"author_association":"NONE","body":"On the ESP32, an extra delay of about 5 microseconds is inserted into the signal output every millisecond. This is far outside the Neopixel timing tolerance of 150 ns, so it leads to incorrect values in some of the pixels.\r\n\r\nThe data for up to 33 RGB pixels can be transmitted in less than one millisecond (1.25 uS per bit X 24 bits per pixel X 33 pixels = 990 uS). In the common case where the show() method call immediately follows a delay() function call, the problem is not encountered unless the strand has at least 34 RGB pixels. However, if the code keeps time some other way (such as by calling millis() repeatedly) the extra delay may occur with random alignment to the signal. In that case, the signal may be corrupted with even a single pixel strand.\r\n\r\nThe extra delay may also be avoided by disabling interrupts during the call to the show() method. In the ESP32 Arduino environment, this cannot be done in the usual way, by calling noInterrupts() -- that function is defined to be nothing in Arduino.h. It can, however, be accomplished by invoking the macro portDISABLE_INTERRUPTS() defined by FreeRTOS in the file portmacro.h, since the Arduino code in the ESP32 is actually running on top of FreeRTOS. The macro portENABLE_INTERRUPTS() re-enables interrupts. Of course, if this method is used, any other time-critical operations will suffer interference, probably including millisecond timekeeping.\r\n\r\n## Method to Reproduce\r\n\r\nThe best way is to observe the output signal on a logic analyzer. Use any sketch that talks to pixels, and set the number of pixels to at least 34. In each burst of activity on the signal line representing a single strand update, you should see at least one pulse (high or low) of between 5 and 6 uS, and those pulses should occur every millisecond thereafter (when the millisecond coincides with signal activity).\r\n\r\nIf no logic analyzer is available, you can see the problem with just a strand of pixels. If a strand of more than 33 pixels is available, simply hook it up and try to run any of the example sketches. Flaky pixels will be visible.\r\n\r\nIf no long strand of pixels is available, the following sketch will illustrate the problem with whatever length strand you do have. Because the strand is short, the extra pulse will only occur some fraction of the time, so you may have to watch for a while to see flaky pixels. (This is how I originally discovered the problem. I use this method of timekeeping when I need to process more than one time-critical device.)\r\n\r\n```\r\n#include <Adafruit_NeoPixel.h>\r\n\r\nunsigned long tickTime = millis();\r\n\r\n#define PIN 17\r\n#define FRAME_INTERVAL 50\r\n\r\n// Parameters set for the 24-Neopixel ring of RGB (no white) pixels\r\n#define NUM_LEDS 24\r\nAdafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, PIN, NEO_GRB + NEO_KHZ800);\r\n\r\nvoid setup() {\r\n  strip.begin();\r\n  strip.show(); // Initialize all pixels to 'off'\r\n}\r\n\r\nvoid loop() {\r\n  if(millis() >= tickTime)\r\n  {\r\n    colorWipeUpdate(strip.Color(0, 255, 0));\r\n    tickTime = millis() + FRAME_INTERVAL;\r\n//    delay(1);                     // one partial workaround\r\n//    portDISABLE_INTERRUPTS();     // the other workaround\r\n    strip.show();\r\n//    portENABLE_INTERRUPTS();\r\n  }\r\n      \r\n}\r\n\r\n// One frame update of the usual colorWipe demo function\r\nvoid colorWipeUpdate(uint32_t c) {\r\n  static uint16_t numLitPixels = 0;\r\n  \r\n  strip.setPixelColor(numLitPixels, c);\r\n  numLitPixels++;\r\n  if(numLitPixels >= strip.numPixels())\r\n    numLitPixels = 0;\r\n}\r\n\r\n```\r\n## Workarounds\r\n\r\nIf your sketch is written so that every call to the show() method always follows immediately after a call to delay(), you can use up to 33 pixels in a strand without a problem. (Note: delay(0) doesn't work, it has to be at least delay(1).) The provided example sketches work this way.\r\n\r\nIf your sketch keeps time some other way, you can add a delay(1) call immediately before each call to the show() method, and use up to 33 pixels in a strand without a problem.\r\n\r\nIf you must have strands of 34 or more pixels, your only choice is to disable interrupts as described above and suffer the consequences.\r\n\r\n## Suggested Solution\r\n\r\nThe problem is pretty fundamental. The only way to prevent the extra delay appears to be to disable interrupts, and disabling interrupts for more than a millisecond (much more for long strands) is hardly a good answer.\r\n\r\nSee http://www.insentricity.com/a.cl/268/controlling-ws2812-rgb-leds-from-the-esp32 for an alternative driver design that should avoid this difficulty, if it can be ported to the Arduino environment.\r\n"},"comment":{"url":"https://api.github.com/repos/adafruit/Adafruit_NeoPixel/issues/comments/380056234","html_url":"https://github.com/adafruit/Adafruit_NeoPixel/issues/139#issuecomment-380056234","issue_url":"https://api.github.com/repos/adafruit/Adafruit_NeoPixel/issues/139","id":380056234,"user":{"login":"mouridis","id":33179613,"avatar_url":"https://avatars2.githubusercontent.com/u/33179613?v=4","gravatar_id":"","url":"https://api.github.com/users/mouridis","html_url":"https://github.com/mouridis","followers_url":"https://api.github.com/users/mouridis/followers","following_url":"https://api.github.com/users/mouridis/following{/other_user}","gists_url":"https://api.github.com/users/mouridis/gists{/gist_id}","starred_url":"https://api.github.com/users/mouridis/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mouridis/subscriptions","organizations_url":"https://api.github.com/users/mouridis/orgs","repos_url":"https://api.github.com/users/mouridis/repos","events_url":"https://api.github.com/users/mouridis/events{/privacy}","received_events_url":"https://api.github.com/users/mouridis/received_events","type":"User","site_admin":false},"created_at":"2018-04-10T10:46:58Z","updated_at":"2018-04-10T10:46:58Z","author_association":"NONE","body":"Unfortunately I based my WS2812B hardware application on ESP32 before doing thorough checking (in my prototype I used a strip of 30 LEDs while the final project, for which I already printed PCBs, uses 120 LEDs). As you can imagine, there are glitches all over the place after LED #32.\r\n\r\nAs expected, using delay() doesn't help in my case of 120 LEDs.\r\n\r\nWhat I find odd though, is that even if I use the portDISABLE_INTERRUPTS() \"workaround\" the problem does not disappear completely. In theory, even though disabling interrupts introduces so many other problems, it should totally fix the glitches in the LEDs. In practice, in my case, the glitches are reduced 90% but not completely disappear.\r\n\r\nAnyway, that's my 2 cents on the issue. Since I have a custom PCBA with ESP32 and 120 WS2812B sitting there, I can help with any debugging you guys may need."}}
{"actor":{"display_login":"mouridis"}}