Use Timer and I2S to generate a sine signal -> I2S play problem



  • At first, we use K210 to generate a random sine signal, and use the oscilloscope to show the wave shape. This works and the relevant code is shown below.

    0_1563548834824_d96b935a-1f20-4c3f-b171-4da65e0d38b8-image.png

    But when we use Timer to generate a pre-designed signal, we can actually store every sampled points' values on the sine signal in an array, but we cannot generate, or play it through the I2S.
    We do not know what the problem is:(

    Please help us, do thank you very much! Or you can also share any of your idea with us.

    Here is our code:

    #include <fpioa.h>
    #include <i2s.h>
    #include <math.h>
    #include <plic.h>
    #include <pwm.h>
    #include <stdint.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sysctl.h>
    #include <syslog.h>
    #include <timer.h>
    #include <uarths.h>
    
    #define POINT 1024U
    #define PI 3.1415926
    #define RX_BUF_THRESHOLD (1024 * 8)
    #define MAX_BUF_LEN (1024 * 16)
    
    static int ctx_table[TIMER_DEVICE_MAX * TIMER_CHANNEL_MAX];
    
    /* Must use volatile variable */
    volatile static int irq_count;
    int16_t sin_data[POINT];
    
    void print_points(int count) {
      int temp;
      if (count <= POINT) {
        temp = (int32_t)(1024 * 10 * cosf(2 * PI * count / POINT));
        sin_data[count - 1] = (int32_t)temp;
      }
    }
    
    int timer_callback(void *ctx) {
      int number = *(int *)ctx;
    
      irq_count++;
    
      /* WARN: Do not use printf in interrupt, here just for demo */
      LOGD(__func__, "Timer callback [%d], count [%d]", number, irq_count);
      print_points(irq_count);
      printf("irq_count:%d; sine value: %d\n", irq_count, sin_data[irq_count - 1]);
      return 0;
    }
    
    void io_mux_init(void) {
      fpioa_set_function(33, FUNC_I2S0_OUT_D1);
      fpioa_set_function(35, FUNC_I2S0_SCLK);
      fpioa_set_function(34, FUNC_I2S0_WS);
    }
    
    int main(void) {
      LOGI(__func__,
           "Kendryte "__DATE__
           " " __TIME__);
      LOGI(__func__, "Timer test");
      sysctl_pll_set_freq(SYSCTL_PLL0, 320000000UL);
      sysctl_pll_set_freq(SYSCTL_PLL1, 160000000UL);
      sysctl_pll_set_freq(SYSCTL_PLL2, 45158400UL);
      uarths_init();
    
      io_mux_init();
      printf("I2S1 INT test...\n");
    
      dmac_init();
      i2s_init(I2S_DEVICE_0, I2S_TRANSMITTER, 0x0C);
      /* Init context table */
      for (size_t i = 0; i < TIMER_DEVICE_MAX * TIMER_CHANNEL_MAX; i++) {
        ctx_table[i] = i;
      }
    
      /* Clear IRQ count */
      irq_count = 0;
    
      /* Init Platform-Level Interrupt Controller(PLIC) */
      plic_init();
      /* Enable global interrupt for machine mode of RISC-V */
      sysctl_enable_irq();
    
      while (irq_count < POINT) {
        for (size_t j = 0; j < TIMER_DEVICE_MAX; j++) {
          /* For every timer devices , Init timer */
          timer_init(j);
          for (size_t i = 0; i < TIMER_CHANNEL_MAX; i++) {
            /* Set timer interval to 500ms */
            timer_set_interval(j, i, 200000000);
            /* Set timer callback function with single shot method */
            timer_irq_register(j, i, 1, 1, timer_callback,
                               &ctx_table[j * TIMER_CHANNEL_MAX + i]);
    
            /* Enable timer */
            timer_set_enable(j, i, 1);
            LOGD(__func__, "Timer enable (%ld, %ld)=>(%ld)", j, i,
                 j * TIMER_CHANNEL_MAX + i);
          }
        }
      }
      for (size_t j = 0; j < TIMER_DEVICE_MAX; j++) {
        /* For every timer devices */
        for (size_t i = 0; i < TIMER_CHANNEL_MAX; i++) {
          /* Disable timer */
          timer_set_enable(j, i, 0);
          /* Deregister every channel timer interrupt */
          timer_irq_unregister(j, i);
        }
      }
      LOGI("[PASS]", "Sine data OK");
    
      i2s_tx_channel_config(
          I2S_DEVICE_0, I2S_CHANNEL_1, RESOLUTION_16_BIT, SCLK_CYCLES_32,
          /*TRIGGER_LEVEL_1*/ TRIGGER_LEVEL_4, RIGHT_JUSTIFYING_MODE);
    
      printf("%d\n", sin_data[256]);
    
      while (1) {
        i2s_play(I2S_DEVICE_0, DMAC_CHANNEL0, (uint8_t *)sin_data, sizeof(sin_data),
                 512, 16, 2);
        return 0;
      }
    }