Parallel Out I2S with DMA Interrupts

willz1200
Posts: 11
Joined: Tue Oct 30, 2018 4:28 pm
Location: United Kingdom
Contact:

Parallel Out I2S with DMA Interrupts

Postby willz1200 » Mon Jan 21, 2019 1:04 pm

Hello,

I'm using the I2S driver to output in 16-bit parallel mode with two buffer to allow nonstop transmission, my aim is to use the I2S_OUT_DONE_INT_RAW interrupt to call a function which updates the buffer that has just been output via DMA, meanwhile the second buffer will be output via dma, until the done interrupt is called allowing me to refill the buffer and so on.

I'm having trouble getting my interrupt setup correctly the program will run but my interrupt is never called, I have verified that the parallel I2S is working with a logic analyzer.

Please can you take a look at the code I'm using to setup the interrupt and spot any issues with it?

Code: Select all

static intr_handle_t my_interrupt_handle;

static void IRAM_ATTR dmaInt(void* arg) {
    printf("Buffer Transferred");
    //Code to fill buffer that was just transferred. 
}

void app_main()
{
    //Other code to setup the I2S
    
    I2S1.int_clr.val = I2S1.int_raw.val;
    I2S1.int_ena.val = 0;
    I2S1.int_ena.out_done = 1;   //Maybe I2S_OUT_DONE_INT_RAW
    
    //Setup I2S DMA Interrupt
    esp_err_t err = esp_intr_alloc(
        ETS_I2S1_INTR_SOURCE,
        ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_LEVEL1 | ESP_INTR_FLAG_IRAM,
        &dmaInt,
        NULL,
        &my_interrupt_handle
    );

    //Enable the Interrupt
    ESP_ERROR_CHECK(esp_intr_enable(my_interrupt_handle));
}
Useful topics for using I2S parallel output:
https://www.esp32.com/viewtopic.php?f=13&t=3256
https://www.esp32.com/viewtopic.php?f=17&t=3188
https://github.com/har-in-air/ESP32-LCD-I2S

Useful I2S Interrupt Example:
https://github.com/nkolban/esp32-snippe ... ls/I2S.cpp

Thanks,
Will

ESP_Sprite
Posts: 9766
Joined: Thu Nov 26, 2015 4:08 am

Re: Parallel Out I2S with DMA Interrupts

Postby ESP_Sprite » Tue Jan 22, 2019 1:45 am

No idea why that interrupt is not firing (maybe something to do with your DMA descriptors?) but the canonical way to do this is to create a circular DMA buffer and use the EOF interrupt, which fires as soon as a DMA link with the EOF bit set has been sent. The code is a bit ugly, but perhaps this helps.

ESP_houwenxiang
Posts: 118
Joined: Tue Jun 26, 2018 3:09 am

Re: Parallel Out I2S with DMA Interrupts

Postby ESP_houwenxiang » Tue Jan 22, 2019 11:56 am

Hi,
Can you provide you DMA link, maybe your DMA linked list is a circular list,
wookooho

ESP_houwenxiang
Posts: 118
Joined: Tue Jun 26, 2018 3:09 am

Re: Parallel Out I2S with DMA Interrupts

Postby ESP_houwenxiang » Tue Jan 22, 2019 1:12 pm

You can use i2s_out_eof interrupt, be sure that eof field in the DMA descriptor is set to 1.
wookooho

willz1200
Posts: 11
Joined: Tue Oct 30, 2018 4:28 pm
Location: United Kingdom
Contact:

Re: Parallel Out I2S with DMA Interrupts

Postby willz1200 » Tue Jan 22, 2019 1:39 pm

I'm looking over the printer cartridge driver that Sprite_tm has written, its a great starting point thanks! Have you released the code for the HTML5 web interface to modify the signals in real time? I just saw it on your have a Hackaday video :D

Heres what I've got so far (I'll change it now I've seen the printer driver :lol: ):

Code: Select all

#define FRAME_SIZE 256
static intr_handle_t my_interrupt_handle;

static void IRAM_ATTR dmaInt(void* arg) {
  gpio_set_level(32, 1); //Should show a pulse on the logic analyzer when an interrupt occurs
  gpio_set_level(32, 0);
}

void app_main()
{
    OutputBuffer[0]=heap_caps_malloc(FRAME_SIZE*2, MALLOC_CAP_DMA);
    memset(OutputBuffer[0], 0, FRAME_SIZE*2);
    assert(OutputBuffer[0] && "Can't allocate memory");

    OutputBuffer[1]=heap_caps_malloc(FRAME_SIZE*2, MALLOC_CAP_DMA);
    memset(OutputBuffer[1], 0, FRAME_SIZE*2);
    assert(OutputBuffer[1] && "Can't allocate memory");

    i2s_parallel_buffer_desc_t bufdesc[2];
    i2s_parallel_config_t cfg={
        .gpio_bus={2, 4, 5, 9, 10, 12, 13, 14, 15, 18, 19, 21, 22, 23, 25, 26},
        .gpio_clk=27,
        .bits=I2S_PARALLEL_BITS_16,
        .clkspeed_hz=8*1000*1000,
        .bufa=&bufdesc[0],
        .bufb=&bufdesc[1],
    };

    bufdesc[0].memory = OutputBuffer[0];
    bufdesc[0].size = FRAME_SIZE*2;

    bufdesc[1].memory = OutputBuffer[1]; 
    bufdesc[1].size = FRAME_SIZE*2;
    
     gpio_set_direction(32, GPIO_MODE_OUTPUT);
    
    i2s_parallel_setup(&I2S1, &cfg);
    
    I2S1.int_clr.val = I2S1.int_raw.val;
    I2S1.int_ena.val = 0;
    I2S1.int_ena.out_done = 1;   //Maybe I2S_OUT_DONE_INT_RAW
    
    //Setup I2S DMA Interrupt
    esp_err_t err = esp_intr_alloc(
        ETS_I2S1_INTR_SOURCE,
        ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_LEVEL1 | ESP_INTR_FLAG_IRAM,
        &dmaInt,
        NULL,
        &my_interrupt_handle
    );

    ESP_ERROR_CHECK(esp_intr_enable(my_interrupt_handle));  //Enable the Interrupt
    
    //Bytes are swapped here because ESP32 is little endian and DMA seems to clock MSB of a word out first...?
    uint16_t *p=OutputBuffer[0];
    p[1]=0B0000000000000001; //Mark start of buffer 1
    p[FRAME_SIZE-2]=0B0000000000000010; //Mark end of butter 1
    
    uint16_t *pp=OutputBuffer[1];
    pp[1]=0B000000000000100; //Mark start of buffer 2
    pp[FRAME_SIZE-2]=0B000000000001000; //Mark end of buffer 2
    
    while (1){
      //main loop
    }
}
part of i2s_parallel.c:

Code: Select all

static void fill_dma_desc(volatile lldesc_t *dmadesc, i2s_parallel_buffer_desc_t *bufdesc) {
    int n=0;
    
    int len=bufdesc->size;
    uint8_t *data=(uint8_t*)bufdesc->memory;
    while(len) {
        int dmalen=len;
        if (dmalen>DMA_MAX) dmalen=DMA_MAX;
        dmadesc[n].size=dmalen;
        dmadesc[n].length=dmalen;
        dmadesc[n].buf=data;
        dmadesc[n].eof=0;
        dmadesc[n].sosf=0;
        dmadesc[n].owner=1;
        dmadesc[n].qe.stqe_next=(lldesc_t*)&dmadesc[n+1];
        dmadesc[n].offset=0;
        len-=dmalen;
        data+=dmalen;
        n++;
    }

    dmadesc[n-1].qe.stqe_next=(lldesc_t*)&dmadesc[0];
    printf("fill_dma_desc: filled %d descriptors\n", n);
}

willz1200
Posts: 11
Joined: Tue Oct 30, 2018 4:28 pm
Location: United Kingdom
Contact:

Re: Parallel Out I2S with DMA Interrupts

Postby willz1200 » Tue Jan 22, 2019 2:42 pm

I've managed to find your waveform generator such a neat little tool thanks! How did you go about outputting the hex data on the ESP32 during testing?

ESP_Sprite
Posts: 9766
Joined: Thu Nov 26, 2015 4:08 am

Re: Parallel Out I2S with DMA Interrupts

Postby ESP_Sprite » Wed Jan 23, 2019 2:27 am

I used a webserver to serve those files, including a cgi to receive the hex values from the browser. Code is in the git repo (need to git clone this url for it to work) if you want to take a look, but be warned, I never really cleaned up that code.

willz1200
Posts: 11
Joined: Tue Oct 30, 2018 4:28 pm
Location: United Kingdom
Contact:

Re: Parallel Out I2S with DMA Interrupts

Postby willz1200 » Thu Jan 24, 2019 1:10 am

I'm quite new to the esp-idf and having trouble getting the "check_waveform" code to run correctly. I cloned it with

Code: Select all

git clone --recurse-submodules -j8 http://git.spritesserver.nl/printcart.git/
then compiled with make flash, but an error came up about a line containing only

Code: Select all

>>>>>>HEAD
in the libesphttpd flash component. I removed it because it didn't seem to make sense and it compiled fine, but the esp32 is now repeatedly crashing. Are there any other commands that need to be ran? Maybe to flash the file system over?

Also I'm using an ESP32-PICO-D4

Thanks,
Will

ESP_Sprite
Posts: 9766
Joined: Thu Nov 26, 2015 4:08 am

Re: Parallel Out I2S with DMA Interrupts

Postby ESP_Sprite » Thu Jan 24, 2019 3:01 am

Heh, as I said, it's not the cleanest repo ever... I may have a bad ref to an uncommitted esphttpd in there. Will check. Do you have a backtrace of what and how it crashed?

willz1200
Posts: 11
Joined: Tue Oct 30, 2018 4:28 pm
Location: United Kingdom
Contact:

Re: Parallel Out I2S with DMA Interrupts

Postby willz1200 » Fri Jan 25, 2019 2:15 pm

Yes it looks like a bad version of libesphttpd is being referenced.

Error before commenting out lines.

Code: Select all

/home/william/esp/printcart/cw/components/libesphttpd/util/cgiflash.c: In function 'cgiUploadFirmware':
/home/william/esp/printcart/cw/components/libesphttpd/util/cgiflash.c:303:1: error: expected expression before '<<' token
 <<<<<<< HEAD
 ^
/home/william/esp/printcart/cw/components/libesphttpd/util/cgiflash.c:307:1: error: expected expression before '>>' token
 >>>>>>> c08b304e8b907287af7580510db4c6323eeb052c
 ^
Reboot cycle containing backtrace

Code: Select all

ets Jun  8 2016 00:22:57

rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
flash read err, 1000
ets_main.c 371 
ets Jun  8 2016 00:22:57

rst:0x10 (RTCWDT_RTC_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 188777542, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:5816
load:0x40078000,len:9176
load:0x40080000,len:6008
0x40080000: _iram_start at /home/william/esp/esp-idf/components/freertos/xtensa_vectors.S:1685

entry 0x4008032c
0x4008032c: _KernelExceptionVector at ??:?

I (30) boot: ESP-IDF v3.1.2 2nd stage bootloader
I (30) boot: compile time 13:47:40
I (30) boot: Enabling RNG early entropy source...
I (34) boot: SPI Speed      : 40MHz
I (39) boot: SPI Mode       : DIO
I (43) boot: SPI Flash Size : 4MB
I (47) boot: Partition Table:
I (50) boot: ## Label            Usage          Type ST Offset   Length
I (57) boot:  0 nvs              WiFi data        01 02 00009000 00006000
I (65) boot:  1 phy_init         RF data          01 01 0000f000 00001000
I (72) boot:  2 factory          factory app      00 00 00010000 00100000
I (80) boot: End of partition table
I (84) esp_image: segment 0: paddr=0x00010020 vaddr=0x3f400020 size=0x37544 (226628) map
I (172) esp_image: segment 1: paddr=0x0004756c vaddr=0x3ffb0000 size=0x031cc ( 12748) load
I (178) esp_image: segment 2: paddr=0x0004a740 vaddr=0x3ffb31cc size=0x00000 (     0) load
I (179) esp_image: segment 3: paddr=0x0004a748 vaddr=0x40080000 size=0x00400 (  1024) load
0x40080000: _iram_start at /home/william/esp/esp-idf/components/freertos/xtensa_vectors.S:1685

I (188) esp_image: segment 4: paddr=0x0004ab50 vaddr=0x40080400 size=0x054c0 ( 21696) load
I (206) esp_image: segment 5: paddr=0x00050018 vaddr=0x400d0018 size=0x69470 (431216) map
0x400d0018: _stext at ??:?

I (357) esp_image: segment 6: paddr=0x000b9490 vaddr=0x400858c0 size=0x0af1c ( 44828) load
0x400858c0: lmacTxFrame at ??:?

I (376) esp_image: segment 7: paddr=0x000c43b4 vaddr=0x400c0000 size=0x00000 (     0) load
I (376) esp_image: segment 8: paddr=0x000c43bc vaddr=0x50000000 size=0x00000 (     0) load
I (393) boot: Loaded app from partition at offset 0x10000
I (393) boot: Disabling RNG early entropy source...
I (395) cpu_start: Pro cpu up.
I (398) cpu_start: Starting app cpu, entry point is 0x40080fcc
0x40080fcc: call_start_cpu1 at /home/william/esp/esp-idf/components/esp32/cpu_start.c:231

I (0) cpu_start: App cpu up.
I (409) heap_init: Initializing. RAM available for dynamic allocation:
I (416) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (422) heap_init: At 3FFB9270 len 00026D90 (155 KiB): DRAM
I (428) heap_init: At 3FFE0440 len 00003BC0 (14 KiB): D/IRAM
I (434) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (441) heap_init: At 400907DC len 0000F824 (62 KiB): IRAM
I (447) cpu_start: Pro cpu start user code
I (129) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
I (198) wifi: wifi driver task: 3ffc05b8, prio:23, stack:3584, core=0
I (198) wifi: wifi firmware version: d5da5a5
I (198) wifi: config NVS flash: enabled
I (208) wifi: config nano formating: disabled
I (208) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
I (218) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
I (248) wifi: Init dynamic tx buffer num: 32
I (248) wifi: Init data frame dynamic rx buffer num: 32
I (248) wifi: Init management frame dynamic rx buffer num: 32
I (248) wifi: Init static rx buffer size: 1600
I (258) wifi: Init static rx buffer num: 10
I (258) wifi: Init dynamic rx buffer num: 32
I (328) phy: phy_version: 4000, b6198fa, Sep  3 2018, 15:11:06, 0, 0
I (328) wifi: mode : sta (d8:a0:1d:40:75:64)
Esp magic: 73665345 (should be 73665345)
Httpd init
esphttpd: active and listening to connections.
Sel add listen 54
Setting up parallel I2S bus at I2S1
Guru Meditation Error: Core  0 panic'ed (IllegalInstruction). Exception was unhandled.
Core 0 register dump:
PC      : 0x400e67ca  PS      : 0x00060d30  A0      : 0x800d2e78  A1      : 0x3ffbae80  
0x400e67ca: periph_module_enable at /home/william/esp/esp-idf/components/driver/periph_ctrl.c:32

A2      : 0x3ff6d000  A3      : 0x3ffbaea0  A4      : 0x00004000  A5      : 0x20000001  
A6      : 0x00000001  A7      : 0x0000001a  A8      : 0x800d3312  A9      : 0x3ffbae60  
A10     : 0x00000007  A11     : 0x0000001a  A12     : 0x8008b82a  A13     : 0x3ffc7480  
A14     : 0x00000003  A15     : 0x00060023  SAR     : 0x00000009  EXCCAUSE: 0x00000000  
EXCVADDR: 0x00000000  LBEG    : 0x400014fd  LEND    : 0x4000150d  LCOUNT  : 0xffffffff  

Backtrace: 0x400e67ca:0x3ffbae80 0x400d2e75:0x3ffbaea0 0x400d2b3b:0x3ffbaf40 0x400d0e06:0x3ffbb080
0x400e67ca: periph_module_enable at /home/william/esp/esp-idf/components/driver/periph_ctrl.c:32

0x400d2e75: cgiWaveformInit at /home/william/esp/printcart/cw/main/cgi-waveform.c:52

0x400d2b3b: app_main at /home/william/esp/printcart/cw/main/main.c:191

0x400d0e06: main_task at /home/william/esp/esp-idf/components/esp32/cpu_start.c:476


Rebooting...
I've also tried changing to the newest version of libesphttpd myself, cloning it from here into the components folder and then copying over component.mk & Kconfig for original the libesphttpd. It gives me the following error:

Code: Select all

/home/william/esp/cw/components/esp-libesphttpd/include/esp8266.h:10:28: fatal error: user_interface.h: No such file or directory
compilation terminated.

Who is online

Users browsing this forum: No registered users and 172 guests