kendryte / kendryte-freertos-demo

Demo of kendryte k210 FreeRTOS SDK
https://github.com/kendryte/kendryte-freertos-sdk
64 stars 24 forks source link

ws2812 with GPIO doesn't work #7

Open Moo2017 opened 5 years ago

Moo2017 commented 5 years ago

Hi all, I need to use bit-banging instead of SPI for ws2812 since I don't have free SPI port, I noticed that it's already implemented for Standalone-sdk , I made required changes to be able to use that in FreedRtos-sdk but unfortunately it doesn't work. Puls width is 5us instead of 900ns (both low and high level time are about 2.6us instead while it should be around 300/600 ns.

GongT commented 5 years ago

Can you run ws2812 demo (edit to use GPIO)?

Moo2017 commented 5 years ago

Sorry I didn’t get what you mean.I can run demo using Spi. I tried to use Gpio but didn’t work ( while it works on Standalone Sdk )

GongT commented 5 years ago

GPIO not always work well, it's timing not accurate.
And it will waste a lot of CPU if it works.

I think you can try to use i2s.

On some custom board (other than KD233), spi chip select may also can solve free port problem.

Moo2017 commented 5 years ago

@GongT I've already tried i2s, but it doesn't work too since there is only one function to send data stream to the i2s port " i2s_configure_as_render" and it repeatedly send the last frame of data to the i2s port, I tried to use i2s_stop function but then if you try to start i2s again it crashes. I posted the issue with i2s but nobody has responded yet!

xiangbingj commented 5 years ago

When FreeRTOS I2S open, it will use DMA to transmit data. The stop interface does not stop DMA transmission. This i2s driver is only designed for audio. To control ws2812, user programs need to fill data in the buffer by i2s_get_buffer and i2s_release_buffer continuously.DMA will transmit data continuously.You can show me your test code.

Moo2017 commented 5 years ago

@xiangbingj Thanks for your reply. Yes I know it's designed for audio , I don't understand why it keep transmitting even for audio it always repeat the last frame which may not be appropriate. However, here is my sample code:

uint32_t blue_color[] = { 0x88888888, 0x88888888, 0x77777777, }; uint32_t green_color[] = { 0x77777777, 0x88888888, 0x88888888, }; uint32_t red_color[] = { 0x88888888, 0x77777777, 0x88888888, };

void init_i2s(void) { i2s_stop(i2s2); i2s_config_as_render(i2s2, &audio, 5, I2S_AM_RIGHT, 0xc); i2s_start(i2s2); }

void send_data(size_t total_frames,const uint8_t *ptr) { size_t offset = 0; size_t reset_frames = total_frames;

uint8_t *buffer = NULL;

while (reset_frames) { size_t frames; i2s_get_buffer(i2s2, &buffer, &frames);

  frames = min(frames, reset_frames);

  size_t buffer_size = frames * block_align;

  memcpy(buffer, ptr + offset, buffer_size);
  i2s_release_buffer(i2s2, frames);

  offset += buffer_size;
  reset_frames -= frames;

}

}

int main(void) {

 block_align = audio.bits_per_sample / 8 * audio.channels;
size_t total_frames = sizeof(red_color) / block_align;

// uint32_t null_size=219; // uint8_t ptr = NULL; // if (null_size) // { // ptr = (uint8_t ) malloc(null_sizeblock_align); // memset(ptr,0,null_sizeblock_align); // }

  if (i2s2) io_close(i2s2);
  i2s2 = io_open("/dev/i2s2");
  configASSERT(i2s2);
  init_i2s();

uint8_t i=0;

while (1)
{
  send_data(total_frames, i==0 ? green_color : (i==1? blue_color : red_color));

// if (null_size) // send_data(null_size, ptr);

  vTaskDelay(pdMS_TO_TICKS(4000));

  i++;
  if (i>2)  i=0;

}

return 0;

}