Hi, I'm trying do drive WS2812B LEDs (aka neopixels) with the I2S peripheral, using method similar to this https://devzone.nordicsemi.com/nordic/nordic-blog/b/blog/posts/driving-ws2812b-leds-using-i2s-on-the-nordic-nrf52
I got the right signal out of SDOUT pin, provided I also configure LRCK and SCK pins (which I don't need). When I set either or both of the LRCK/SCK pins to 0xffffffff, no signal comes out of the SDOUT pin.
Is it possible to leave the SCK/LRCK disconnected and have the I2S still operate?
The code is below. It also has detects the end of transmission correctly (first TXPTRUPD triggers after the hardware picks up the pointer, so we set the MAXCNT to one more byte and wait for that one to be picked up).
// based on https://electronut.in/nrf52-i2s-ws2812/
static int numIrq;
extern "C" void I2S_IRQHandler()
if (NRF_I2S->EVENTS_TXPTRUPD != 0)
NRF_I2S->EVENTS_TXPTRUPD = 0;
volatile uint32_t dummy = NRF_I2S->EVENTS_TXPTRUPD;
if (numIrq == 0)
NRF_I2S->RXTXD.MAXCNT = 1;
NRF_I2S->ENABLE = 0;
void neopixel_send_buffer(Pin *pin, const uint8_t *data, unsigned size)
int32_t iptr = 0, optr = 6;
uint32_t len = optr + size + optr;
uint32_t *expBuf = new uint32_t[len];
memset(expBuf, 0, len * 4);
while (iptr < (int)size)
uint32_t outp = 0x88888888;
uint8_t inp = data[iptr];
for (int i = 0; i < 8; ++i)
if (inp & (1 << i))
outp |= 0xe << (i * 4);
outp = (outp >> 16) | (outp << 16);
expBuf[optr++] = outp;
NRF_I2S->CONFIG.RXEN = 0;
NRF_I2S->CONFIG.TXEN = 1;
NRF_I2S->CONFIG.MCKEN = 1;
NRF_I2S->CONFIG.MCKFREQ = I2S_CONFIG_MCKFREQ_MCKFREQ_32MDIV10; // 3.2MHz
NRF_I2S->CONFIG.RATIO = I2S_CONFIG_RATIO_RATIO_32X;
NRF_I2S->CONFIG.SWIDTH = I2S_CONFIG_SWIDTH_SWIDTH_16Bit;
NRF_I2S->CONFIG.ALIGN = I2S_CONFIG_ALIGN_ALIGN_Left;
NRF_I2S->CONFIG.FORMAT = I2S_CONFIG_FORMAT_FORMAT_I2S;
NRF_I2S->CONFIG.CHANNELS = I2S_CONFIG_CHANNELS_CHANNELS_Stereo;
NRF_I2S->PSEL.MCK = -1;
NRF_I2S->PSEL.SCK = -1;
NRF_I2S->PSEL.LRCK = -1;
NRF_I2S->PSEL.SDOUT = (uint32_t)pin->name;
NRF_I2S->PSEL.SDIN = -1;
NRF_I2S->PSEL.MCK = -1; // D9
NRF_I2S->PSEL.SCK = 27; // D10
NRF_I2S->PSEL.LRCK = 6; // D11
NRF_I2S->PSEL.SDOUT = 8; // D12
NRF_I2S->PSEL.SDIN = -1; // disconnect
NRF_I2S->TXD.PTR = (uint32_t)expBuf;
NRF_I2S->RXTXD.MAXCNT = len;
NRF_I2S->INTEN = I2S_INTEN_TXPTRUPD_Msk;
numIrq = 0;
NRF_I2S->ENABLE = 1;
NRF_I2S->TASKS_START = 1;
} // namespace codal
It doesn't look like it no, since you don't get a signal when you disconnect them.
Since the creator of this sample isn't associated with Nordic, I suggest you ask him directly about any issues using it.
thank you! I had working code on the nrf52832 that required the SCK pin, but not the LRCK pin. The same code running on the nRF52840 does require the LRCK pin. I couldn't figure out why it wasn't working until I ran into this post.
the LRCK pin was not required on the nrf52832
It is possible to use PWM peripheral with double-buffer and generate the PWM data on the fly from neopixel data. I never got around to implement that though... I saw some examples, but they pre-compute neopixel data, which very memory in-efficient.
yes, i've seen some examples but not a plain reusable library. The i2s solution was the easiest one to implement for me.