ESP32-S3 LCD and I2S FULL documentation

Baldhead
Posts: 468
Joined: Sun Mar 31, 2019 5:16 am

Re: ESP32-S3 LCD and I2S FULL documentation

Postby Baldhead » Wed Dec 22, 2021 10:51 pm

@ESP_Sprite,

I am trying to send the data using fifo mode and the data are "out of order in fifo" i think.

The correct sequence would be:
0x01, 0x02, 0x04, 0x08

But LCD_CAM io output is:
0x08, 0x01, 0x02, 0x04

Could you help me with this ?

Thank's.

EDIT:
At power up:
0x00, 0x00, 0x00, 0x00
0x08, 0x01, 0x02, 0x04
0x08, 0x01, 0x02, 0x04
0x08, 0x01, 0x02, 0x04
.
.
.

Code: Select all

    uint8_t data[4];
    
    data[0] = 0x01;
    data[1] = 0x02;
    data[2] = 0x04;
    data[3] = 0x08;
    
hw_lcd_dma_tx_push_n_data( 0, data, 4 );

inline void hw_lcd_dma_tx_push_n_data( uint32_t channel, uint8_t* data, uint32_t data_len )
{ 
    for( uint32_t i = 0 ; i < data_len ; i++ )
    {       
        while( hw_lcd_dma_L1_fifo_full(channel) );

        GDMA.channel[channel].out.push.outfifo_wdata = data[i];  // This register stores the data that need to be pushed into DMA FIFO.
        GDMA.channel[channel].out.push.outfifo_push = 1;         // Set this bit to push data into DMA FIFO.      
    } 
}
Last edited by Baldhead on Mon Dec 27, 2021 2:32 am, edited 1 time in total.

Baldhead
Posts: 468
Joined: Sun Mar 31, 2019 5:16 am

Re: ESP32-S3 LCD and I2S FULL documentation

Postby Baldhead » Thu Dec 23, 2021 4:39 am

Give me a little help to the last question @ESP_Sprite, please.

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

Re: ESP32-S3 LCD and I2S FULL documentation

Postby ESP_Sprite » Thu Dec 23, 2021 6:30 am

I don't actually know if writing the FIFO directly without going through DMA is actually supported... will ask, but the docs I have do not describe such a procedure. (Edit: Asked, it should work but is indeed a somewhat undocumented and untested feature ) Regardless, perhaps it helps if you reset the fifo beforehand by writing an 1 to LCD_CAM_LCD_AFIFO_RESET (and possibly waiting a few clock cycles)?

Baldhead
Posts: 468
Joined: Sun Mar 31, 2019 5:16 am

Re: ESP32-S3 LCD and I2S FULL documentation

Postby Baldhead » Thu Dec 23, 2021 10:51 pm

ESP_Sprite wrote:
Thu Dec 23, 2021 6:30 am
I don't actually know if writing the FIFO directly without going through DMA is actually supported... will ask, but the docs I have do not describe such a procedure. (Edit: Asked, it should work but is indeed a somewhat undocumented and untested feature ) Regardless, perhaps it helps if you reset the fifo beforehand by writing an 1 to LCD_CAM_LCD_AFIFO_RESET (and possibly waiting a few clock cycles)?
Unfortunately afifo reset doesn't work.

Baldhead
Posts: 468
Joined: Sun Mar 31, 2019 5:16 am

Re: ESP32-S3 LCD and I2S FULL documentation

Postby Baldhead » Thu Dec 23, 2021 11:08 pm

If i send 1 byte at a time, after esp32-s3 power up, the lcd io clock print 8 times with data_0 pin in 0. At nine clock data_0 pin go to 1 and stay printing 1 forever.

The strange thing is that L1FIFO count( GDMA.channel[0].out.outfifo_status.outfifo_cnt_l1 ) increment by 1 every time i put 1 byte in the fifo, until 7, and after reset to 0, ie ( 0,1,2,3,4,5,6,7, 0,1,2,3,4,5,6,7........... ).

The L2FIFO count( GDMA.channel[0].out.outfifo_status.outfifo_cnt_l2 ) stay in 0 all the time.
The L3FIFO count( GDMA.channel[0].out.outfifo_status.outfifo_cnt_l3 ) stay in 0 all the time.

Code: Select all

while(1)
{        
    hw_lcd_write_data( 0x01 );
    vTaskDelay( pdMS_TO_TICKS(1000) );  
}

// LCD_CAM.lcd_user.lcd_always_out_en = 0;
inline void hw_lcd_write_data( uint8_t data )      
{      
    LCD_CAM.lcd_user.lcd_dout_cyclelen = 0;  // send a single byte.

    LCD_CAM.lcd_user.lcd_cmd = 0;   // R/W; bitpos: [26]; default: 0. 1: Be able to send command in LCD sequence when LCD starts. 0: Disable.  
    LCD_CAM.lcd_user.lcd_dout = 1;  // R/W; bitpos: [24]; default: 0. 1: Be able to send data out in LCD sequence when LCD starts. 0: Disable.
     
    hw_lcd_dma_tx_push_data( 0, data );

    LCD_CAM.lcd_user.lcd_update = 1;  // R/W; bitpos: [20]; default: 0. 1: Update LCD registers, will be cleared by hardware. 0 : Not care. Update parameters before start transaction.
    LCD_CAM.lcd_user.lcd_start = 1;   // R/W; bitpos: [27]; default: 0. LCD start sending data enable signal, valid in high level.
}

inline void hw_lcd_dma_tx_push_data( uint32_t channel, uint8_t data )
{    
    printf("dma tx idle: %s\n", hw_lcd_dma_tx_idle(0) ? "IDLE" : "BUSY" );
    
    printf("L1_fifo: %s\n", hw_lcd_dma_L1_fifo_empty(0) ? "EMPTY" : "NOT_EMPTY" );
    printf("L1_fifo: %s\n", hw_lcd_dma_L1_fifo_full(0) ?  "FULL" : "NOT_FULL" );
    printf("L1_count: %u\n\n", hw_lcd_dma_L1_fifo_count(0) );  // GDMA.channel[0].out.outfifo_status.outfifo_cnt_l1

    printf("L2_fifo: %s\n", hw_lcd_dma_L2_fifo_empty(0) ? "EMPTY" : "NOT_EMPTY" );
    printf("L2_fifo: %s\n", hw_lcd_dma_L2_fifo_full(0) ?  "FULL" : "NOT_FULL" );
    printf("L2_count: %u\n\n", hw_lcd_dma_L2_fifo_count(0) );

    printf("L3_fifo: %s\n", hw_lcd_dma_L3_fifo_empty(0) ? "EMPTY" : "NOT_EMPTY" );
    printf("L3_fifo: %s\n", hw_lcd_dma_L3_fifo_full(0) ?  "FULL" : "NOT_FULL" );
    printf("L3_count: %u\n\n", hw_lcd_dma_L3_fifo_count(0) );

    printf("ovf_l1: %s\n", GDMA.channel[channel].out.int_raw.outfifo_ovf_l1 ? "OVERFLOW" : "NOT_OVERFLOW" );
    printf("ovf_l3: %s\n", GDMA.channel[channel].out.int_raw.outfifo_ovf_l3 ? "OVERFLOW" : "NOT_OVERFLOW" );

    printf("udf_l1: %s\n", GDMA.channel[channel].out.int_raw.outfifo_udf_l1 ? "UNDERLOW" : "NOT_UNDERFLOW" );
    printf("udf_l3: %s\n\n\n", GDMA.channel[channel].out.int_raw.outfifo_udf_l3 ? "UNDERLOW" : "NOT_UNDERFLOW" );


    GDMA.channel[channel].out.push.outfifo_wdata = data;  // This register stores the data that need to be pushed into DMA FIFO.
    GDMA.channel[channel].out.push.outfifo_push = 1;      // Set this bit to push data into DMA FIFO.
}  

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

Re: ESP32-S3 LCD and I2S FULL documentation

Postby ESP_Sprite » Fri Dec 24, 2021 1:33 am

Looked it up... the reason you can't put more into the L1FIFO is that it's tiny: only 24 bytes (which I assume is organized in 3 words). I'm not sure why data doesn't get pulled through to l2/l3fifo (especially l2fifo is larger at 128 bytes), perhaps that mechanism only starts when the peripheral starts a transaction.

EDIT: Never mind, I see that push operations only push 8 bit into the FIFO. Hmm, then I can't really explain the l1fifo behaviour you're seeing... will ask to see if the digital team knows more. By the way, it's likely that the bus between l1fifo and l2fifo is larger than 8 bit, so you'd expect the l1fifo to only empty into the l2fifo once the l2fifo collected 32 or maybe even 64 bit. You are sure the fill numbers there do not change even if you put >8 bytes into the l1fifo?

Baldhead
Posts: 468
Joined: Sun Mar 31, 2019 5:16 am

Re: ESP32-S3 LCD and I2S FULL documentation

Postby Baldhead » Sat Dec 25, 2021 5:29 pm

@ESP_Sprite,

Why "GDMA.channel[channel].out.push.outfifo_wdata" is 9 bit wide ?
Last edited by Baldhead on Mon Dec 27, 2021 1:34 am, edited 1 time in total.

Baldhead
Posts: 468
Joined: Sun Mar 31, 2019 5:16 am

Re: ESP32-S3 LCD and I2S FULL documentation

Postby Baldhead » Mon Dec 27, 2021 1:34 am

ESP_Sprite wrote:
Fri Dec 24, 2021 1:33 am
Looked it up... the reason you can't put more into the L1FIFO is that it's tiny: only 24 bytes (which I assume is organized in 3 words). I'm not sure why data doesn't get pulled through to l2/l3fifo (especially l2fifo is larger at 128 bytes), perhaps that mechanism only starts when the peripheral starts a transaction.

EDIT: Never mind, I see that push operations only push 8 bit into the FIFO. Hmm, then I can't really explain the l1fifo behaviour you're seeing... will ask to see if the digital team knows more. By the way, it's likely that the bus between l1fifo and l2fifo is larger than 8 bit, so you'd expect the l1fifo to only empty into the l2fifo once the l2fifo collected 32 or maybe even 64 bit. You are sure the fill numbers there do not change even if you put >8 bytes into the l1fifo?
Hi @ESP_Sprite,

My observations (i don't know if they are correct or not):

L1 only transfer to L2 when L1 have 8 bytes.

L1 count unit is byte ( GDMA.channel[channel].out.outfifo_status.outfifo_cnt_l1 = 1 is equal to 1 byte )
L2 count unit is 8 byte ( GDMA.channel[channel].out.outfifo_status.outfifo_cnt_l2 = 1 is equal to 8 bytes )
L3 count uint is byte ( GDMA.channel[channel].out.outfifo_status.outfifo_cnt_l3 = 1 is equal to 1 byte )

Esp32-s3 technical reference manual: Pre-release v0.3, page 108
GDMA_OUTFIFO_CNT_L1_CHn The register stores the byte number of the data in L1 TX FIFO for TX channel 0. (RO)
GDMA_OUTFIFO_CNT_L2_CHn The register stores the byte number of the data in L2 TX FIFO for TX channel 0. (RO)
GDMA_OUTFIFO_CNT_L3_CHn The register stores the byte number of the data in L3 TX FIFO for TX channel 0. (RO)

Esp32-s3 technical reference manual: Pre-release v0.3, page 78
L1FIFO, L2FIFO and L3FIFO have fixed depth: 24, 128, and 16 bytes, respectively.

L1 size = 16 bytes
L2 size = 80 bytes
L3 size = 16 bytes

// gdma_struct.h
GDMA.sram_size[channel].out.out_size = 8; // This register is used to configure the size of L2 Tx FIFO for Tx channel 0.
// 0:16 bytes. 1:24 bytes. 2:32 bytes. 3: 40 bytes. 4: 48 bytes. 5:56 bytes. 6: 64 bytes. 7: 72 bytes. 8: 80 bytes.

All multiples of 8: ( relevant or not?! )
0: 16 bytes = 2*8
1: 24 bytes = 3*8
2: 32 bytes = 4*8
3: 40 bytes = 5*8
4: 48 bytes = 6*8
5: 56 bytes = 7*8
6: 64 bytes = 8*8
7: 72 bytes = 9*8
8: 80 bytes = 10*8

Code: Select all

void app_main(void)
{  
    esp_err_t r = hw_lcd_init();
    printf("r = %s\n\n", esp_err_to_name(r));
    
    uint8_t data[32];
    
    data[0] = 0x01;
    data[1] = 0x02;
    data[2] = 0x04;
    data[3] = 0x08;
    data[4] = 0x10;
    data[5] = 0x20;
    data[6] = 0x40;
    data[7] = 0x80;
    data[8] = 0x11;
    data[9] = 0x22;
    
    while(1)
    {        
        hw_lcd_write_n_data( 0x02, data, 10 );
        vTaskDelay( pdMS_TO_TICKS(1000) );   
    }
}


inline void hw_lcd_write_n_data( uint32_t command, uint8_t* data, uint32_t data_len )      
{           
    LCD_CAM.lcd_user.lcd_dout_cyclelen = data_len - 1;  // 0 = 1 single byte. LCD_CAM.lcd_user.lcd_always_out_en = 0;

    LCD_CAM.lcd_user.lcd_cmd = 1;   
    LCD_CAM.lcd_user.lcd_dout = 1;
    
    LCD_CAM.lcd_cmd_val.lcd_cmd_value = command;
     
    hw_lcd_dma_tx_push_n_data( 0, data, data_len );

//    LCD_CAM.lcd_user.lcd_update = 1;  
//    LCD_CAM.lcd_user.lcd_start = 1;   
}


inline void hw_lcd_dma_tx_push_n_data( uint32_t channel, uint8_t* data, uint32_t data_len )
{ 
    printf("\x1b[31m");  // Red text

    printf("dma tx idle: %s\n", hw_lcd_dma_tx_idle(0) ? "IDLE" : "BUSY" );
    
    printf("L1_fifo: %s\n", hw_lcd_dma_L1_fifo_empty(0) ? "EMPTY" : "NOT_EMPTY" );
    printf("L1_fifo: %s\n", hw_lcd_dma_L1_fifo_full(0) ?  "FULL" : "NOT_FULL" );
    printf("L1_count: %u\n\n", hw_lcd_dma_L1_fifo_count(0) );

    printf("L2_fifo: %s\n", hw_lcd_dma_L2_fifo_empty(0) ? "EMPTY" : "NOT_EMPTY" );
    printf("L2_fifo: %s\n", hw_lcd_dma_L2_fifo_full(0) ?  "FULL" : "NOT_FULL" );
    printf("L2_count: %u\n\n", hw_lcd_dma_L2_fifo_count(0) );

    printf("L3_fifo: %s\n", hw_lcd_dma_L3_fifo_empty(0) ? "EMPTY" : "NOT_EMPTY" );
    printf("L3_fifo: %s\n", hw_lcd_dma_L3_fifo_full(0) ?  "FULL" : "NOT_FULL" );
    printf("L3_count: %u\n\n", hw_lcd_dma_L3_fifo_count(0) );

    printf("ovf_l1: %s\n", GDMA.channel[channel].out.int_raw.outfifo_ovf_l1 ? "OVERFLOW" : "NOT_OVERFLOW" );
    printf("ovf_l3: %s\n", GDMA.channel[channel].out.int_raw.outfifo_ovf_l3 ? "OVERFLOW" : "NOT_OVERFLOW" );

    printf("udf_l1: %s\n", GDMA.channel[channel].out.int_raw.outfifo_udf_l1 ? "UNDERLOW" : "NOT_UNDERFLOW" );
    printf("udf_l3: %s\n\n\n", GDMA.channel[channel].out.int_raw.outfifo_udf_l3 ? "UNDERLOW" : "NOT_UNDERFLOW" );

    uint32_t t;
    bool s = 0;

    for( uint32_t i = 0 ; i < data_len ; i++ )
    {       
        // while( hw_lcd_dma_L1_fifo_full(channel) );
        
        t = 0;

        while( hw_lcd_dma_L1_fifo_full(channel) )
        {
            t++;

            if( t == 1000 )
            {
                s = 1;
                goto stop;
            }            
        }

        GDMA.channel[channel].out.push.outfifo_wdata = data[i];  
        GDMA.channel[channel].out.push.outfifo_push = 1;                    
    }

stop:
    printf("\x1b[34m");  // blue text

    printf("dma tx idle: %s\n", hw_lcd_dma_tx_idle(0) ? "IDLE" : "BUSY" );
    
    printf("L1_fifo: %s\n", hw_lcd_dma_L1_fifo_empty(0) ? "EMPTY" : "NOT_EMPTY" );
    printf("L1_fifo: %s\n", hw_lcd_dma_L1_fifo_full(0) ?  "FULL" : "NOT_FULL" );
    printf("L1_count: %u\n\n", hw_lcd_dma_L1_fifo_count(0) );

    printf("L2_fifo: %s\n", hw_lcd_dma_L2_fifo_empty(0) ? "EMPTY" : "NOT_EMPTY" );
    printf("L2_fifo: %s\n", hw_lcd_dma_L2_fifo_full(0) ?  "FULL" : "NOT_FULL" );
    printf("L2_count: %u\n\n", hw_lcd_dma_L2_fifo_count(0) );

    printf("L3_fifo: %s\n", hw_lcd_dma_L3_fifo_empty(0) ? "EMPTY" : "NOT_EMPTY" );
    printf("L3_fifo: %s\n", hw_lcd_dma_L3_fifo_full(0) ?  "FULL" : "NOT_FULL" );
    printf("L3_count: %u\n\n", hw_lcd_dma_L3_fifo_count(0) );

    printf("ovf_l1: %s\n", GDMA.channel[channel].out.int_raw.outfifo_ovf_l1 ? "OVERFLOW" : "NOT_OVERFLOW" );
    printf("ovf_l3: %s\n", GDMA.channel[channel].out.int_raw.outfifo_ovf_l3 ? "OVERFLOW" : "NOT_OVERFLOW" );

    printf("udf_l1: %s\n", GDMA.channel[channel].out.int_raw.outfifo_udf_l1 ? "UNDERLOW" : "NOT_UNDERFLOW" );
    printf("udf_l3: %s\n\n\n", GDMA.channel[channel].out.int_raw.outfifo_udf_l3 ? "UNDERLOW" : "NOT_UNDERFLOW" ); 

    if( s )
        while(1);
}
ESP-IDF MONITOR:

Code: Select all

I (688) HW_LCD_DMA: GDMA HW Version: 0x02101180

I (695) HW_LCD: HW_LCD Information:
I (700) HW_LCD: LCD_CAM HW Version: 33566752
I (705) HW_LCD: HW_LCD_FREQ_HZ = 20 MHz
I (711) HW_LCD: WR io num = 4
I (716) HW_LCD: DC io num = 5
I (720) HW_LCD: CS io num = 6
I (725) HW_LCD: HW_LCD BUS Data Width = 8
I (730) HW_LCD: Data[0] = 7
I (735) HW_LCD: Data[1] = 15
I (739) HW_LCD: Data[2] = 16
I (744) HW_LCD: Data[3] = 17
I (748) HW_LCD: Data[4] = 18
I (753) HW_LCD: Data[5] = 8
I (757) HW_LCD: Data[6] = 3
I (762) HW_LCD: Data[7] = 46
r = ESP_OK

dma tx idle: IDLE
L1_fifo: EMPTY
L1_fifo: NOT_FULL
L1_count: 0

L2_fifo: EMPTY
L2_fifo: NOT_FULL
L2_count: 0

L3_fifo: EMPTY
L3_fifo: NOT_FULL
L3_count: 0

ovf_l1: NOT_OVERFLOW
ovf_l3: NOT_OVERFLOW
udf_l1: NOT_UNDERFLOW
udf_l3: NOT_UNDERFLOW


dma tx idle: IDLE
L1_fifo: NOT_EMPTY
L1_fifo: NOT_FULL
L1_count: 2

L2_fifo: EMPTY
L2_fifo: NOT_FULL
L2_count: 0

L3_fifo: NOT_EMPTY
L3_fifo: NOT_FULL
L3_count: 8

ovf_l1: NOT_OVERFLOW
ovf_l3: NOT_OVERFLOW
udf_l1: NOT_UNDERFLOW
udf_l3: NOT_UNDERFLOW


dma tx idle: IDLE
L1_fifo: NOT_EMPTY
L1_fifo: NOT_FULL
L1_count: 2

L2_fifo: EMPTY
L2_fifo: NOT_FULL
L2_count: 0

L3_fifo: NOT_EMPTY
L3_fifo: NOT_FULL
L3_count: 8

ovf_l1: NOT_OVERFLOW
ovf_l3: NOT_OVERFLOW
udf_l1: NOT_UNDERFLOW
udf_l3: NOT_UNDERFLOW


dma tx idle: IDLE
L1_fifo: NOT_EMPTY
L1_fifo: NOT_FULL
L1_count: 4

L2_fifo: EMPTY
L2_fifo: NOT_FULL
L2_count: 0

L3_fifo: NOT_EMPTY
L3_fifo: FULL
L3_count: 16

ovf_l1: NOT_OVERFLOW
ovf_l3: NOT_OVERFLOW
udf_l1: NOT_UNDERFLOW
udf_l3: NOT_UNDERFLOW


dma tx idle: IDLE
L1_fifo: NOT_EMPTY
L1_fifo: NOT_FULL
L1_count: 4

L2_fifo: EMPTY
L2_fifo: NOT_FULL
L2_count: 0

L3_fifo: NOT_EMPTY
L3_fifo: FULL
L3_count: 16

ovf_l1: NOT_OVERFLOW
ovf_l3: NOT_OVERFLOW
udf_l1: NOT_UNDERFLOW
udf_l3: NOT_UNDERFLOW


dma tx idle: IDLE
L1_fifo: NOT_EMPTY
L1_fifo: NOT_FULL
L1_count: 6

L2_fifo: NOT_EMPTY
L2_fifo: NOT_FULL
L2_count: 1

L3_fifo: NOT_EMPTY
L3_fifo: FULL
L3_count: 16

ovf_l1: NOT_OVERFLOW
ovf_l3: NOT_OVERFLOW
udf_l1: NOT_UNDERFLOW
udf_l3: NOT_UNDERFLOW


dma tx idle: IDLE
L1_fifo: NOT_EMPTY
L1_fifo: NOT_FULL
L1_count: 6

L2_fifo: NOT_EMPTY
L2_fifo: NOT_FULL
L2_count: 1

L3_fifo: NOT_EMPTY
L3_fifo: FULL
L3_count: 16

ovf_l1: NOT_OVERFLOW
ovf_l3: NOT_OVERFLOW
udf_l1: NOT_UNDERFLOW
udf_l3: NOT_UNDERFLOW


dma tx idle: IDLE
L1_fifo: EMPTY
L1_fifo: NOT_FULL
L1_count: 0

L2_fifo: NOT_EMPTY
L2_fifo: NOT_FULL
L2_count: 3

L3_fifo: NOT_EMPTY
L3_fifo: FULL
L3_count: 16

ovf_l1: NOT_OVERFLOW
ovf_l3: NOT_OVERFLOW
udf_l1: NOT_UNDERFLOW
udf_l3: NOT_UNDERFLOW


dma tx idle: IDLE
L1_fifo: EMPTY
L1_fifo: NOT_FULL
L1_count: 0

L2_fifo: NOT_EMPTY
L2_fifo: NOT_FULL
L2_count: 3

L3_fifo: NOT_EMPTY
L3_fifo: FULL
L3_count: 16

ovf_l1: NOT_OVERFLOW
ovf_l3: NOT_OVERFLOW
udf_l1: NOT_UNDERFLOW
udf_l3: NOT_UNDERFLOW


dma tx idle: IDLE
L1_fifo: NOT_EMPTY
L1_fifo: NOT_FULL
L1_count: 2

L2_fifo: NOT_EMPTY
L2_fifo: NOT_FULL
L2_count: 4

L3_fifo: NOT_EMPTY
L3_fifo: FULL
L3_count: 16

ovf_l1: NOT_OVERFLOW
ovf_l3: NOT_OVERFLOW
udf_l1: NOT_UNDERFLOW
udf_l3: NOT_UNDERFLOW


dma tx idle: IDLE
L1_fifo: NOT_EMPTY
L1_fifo: NOT_FULL
L1_count: 2

L2_fifo: NOT_EMPTY
L2_fifo: NOT_FULL
L2_count: 4

L3_fifo: NOT_EMPTY
L3_fifo: FULL
L3_count: 16

ovf_l1: NOT_OVERFLOW
ovf_l3: NOT_OVERFLOW
udf_l1: NOT_UNDERFLOW
udf_l3: NOT_UNDERFLOW


dma tx idle: IDLE
L1_fifo: NOT_EMPTY
L1_fifo: NOT_FULL
L1_count: 4

L2_fifo: NOT_EMPTY
L2_fifo: NOT_FULL
L2_count: 5

L3_fifo: NOT_EMPTY
L3_fifo: FULL
L3_count: 16

ovf_l1: NOT_OVERFLOW
ovf_l3: NOT_OVERFLOW
udf_l1: NOT_UNDERFLOW
udf_l3: NOT_UNDERFLOW


dma tx idle: IDLE
L1_fifo: NOT_EMPTY
L1_fifo: NOT_FULL
L1_count: 4

L2_fifo: NOT_EMPTY
L2_fifo: NOT_FULL
L2_count: 5

L3_fifo: NOT_EMPTY
L3_fifo: FULL
L3_count: 16

ovf_l1: NOT_OVERFLOW
ovf_l3: NOT_OVERFLOW
udf_l1: NOT_UNDERFLOW
udf_l3: NOT_UNDERFLOW


dma tx idle: IDLE
L1_fifo: NOT_EMPTY
L1_fifo: NOT_FULL
L1_count: 6

L2_fifo: NOT_EMPTY
L2_fifo: NOT_FULL
L2_count: 6

L3_fifo: NOT_EMPTY
L3_fifo: FULL
L3_count: 16

ovf_l1: NOT_OVERFLOW
ovf_l3: NOT_OVERFLOW
udf_l1: NOT_UNDERFLOW
udf_l3: NOT_UNDERFLOW


dma tx idle: IDLE
L1_fifo: NOT_EMPTY
L1_fifo: NOT_FULL
L1_count: 6

L2_fifo: NOT_EMPTY
L2_fifo: NOT_FULL
L2_count: 6

L3_fifo: NOT_EMPTY
L3_fifo: FULL
L3_count: 16

ovf_l1: NOT_OVERFLOW
ovf_l3: NOT_OVERFLOW
udf_l1: NOT_UNDERFLOW
udf_l3: NOT_UNDERFLOW


dma tx idle: IDLE
L1_fifo: EMPTY
L1_fifo: NOT_FULL
L1_count: 0

L2_fifo: NOT_EMPTY
L2_fifo: NOT_FULL
L2_count: 8

L3_fifo: NOT_EMPTY
L3_fifo: FULL
L3_count: 16

ovf_l1: NOT_OVERFLOW
ovf_l3: NOT_OVERFLOW
udf_l1: NOT_UNDERFLOW
udf_l3: NOT_UNDERFLOW


dma tx idle: IDLE
L1_fifo: EMPTY
L1_fifo: NOT_FULL
L1_count: 0

L2_fifo: NOT_EMPTY
L2_fifo: NOT_FULL
L2_count: 8

L3_fifo: NOT_EMPTY
L3_fifo: FULL
L3_count: 16

ovf_l1: NOT_OVERFLOW
ovf_l3: NOT_OVERFLOW
udf_l1: NOT_UNDERFLOW
udf_l3: NOT_UNDERFLOW


dma tx idle: IDLE
L1_fifo: NOT_EMPTY
L1_fifo: NOT_FULL
L1_count: 2

L2_fifo: NOT_EMPTY
L2_fifo: NOT_FULL
L2_count: 9

L3_fifo: NOT_EMPTY
L3_fifo: FULL
L3_count: 16

ovf_l1: NOT_OVERFLOW
ovf_l3: NOT_OVERFLOW
udf_l1: NOT_UNDERFLOW
udf_l3: NOT_UNDERFLOW


dma tx idle: IDLE
L1_fifo: NOT_EMPTY
L1_fifo: NOT_FULL
L1_count: 2

L2_fifo: NOT_EMPTY
L2_fifo: NOT_FULL
L2_count: 9

L3_fifo: NOT_EMPTY
L3_fifo: FULL
L3_count: 16

ovf_l1: NOT_OVERFLOW
ovf_l3: NOT_OVERFLOW
udf_l1: NOT_UNDERFLOW
udf_l3: NOT_UNDERFLOW


dma tx idle: IDLE
L1_fifo: NOT_EMPTY
L1_fifo: NOT_FULL
L1_count: 4

L2_fifo: NOT_EMPTY
L2_fifo: FULL
L2_count: 10

L3_fifo: NOT_EMPTY
L3_fifo: FULL
L3_count: 16

ovf_l1: NOT_OVERFLOW
ovf_l3: NOT_OVERFLOW
udf_l1: NOT_UNDERFLOW
udf_l3: NOT_UNDERFLOW


dma tx idle: IDLE
L1_fifo: NOT_EMPTY
L1_fifo: NOT_FULL
L1_count: 4

L2_fifo: NOT_EMPTY
L2_fifo: FULL
L2_count: 10

L3_fifo: NOT_EMPTY
L3_fifo: FULL
L3_count: 16

ovf_l1: NOT_OVERFLOW
ovf_l3: NOT_OVERFLOW
udf_l1: NOT_UNDERFLOW
udf_l3: NOT_UNDERFLOW


dma tx idle: IDLE
L1_fifo: NOT_EMPTY
L1_fifo: NOT_FULL
L1_count: 14

L2_fifo: NOT_EMPTY
L2_fifo: FULL
L2_count: 10

L3_fifo: NOT_EMPTY
L3_fifo: FULL
L3_count: 16

ovf_l1: NOT_OVERFLOW
ovf_l3: NOT_OVERFLOW
udf_l1: NOT_UNDERFLOW
udf_l3: NOT_UNDERFLOW


dma tx idle: IDLE
L1_fifo: NOT_EMPTY
L1_fifo: NOT_FULL
L1_count: 14

L2_fifo: NOT_EMPTY
L2_fifo: FULL
L2_count: 10

L3_fifo: NOT_EMPTY
L3_fifo: FULL
L3_count: 16

ovf_l1: NOT_OVERFLOW
ovf_l3: NOT_OVERFLOW
udf_l1: NOT_UNDERFLOW
udf_l3: NOT_UNDERFLOW


dma tx idle: IDLE
L1_fifo: NOT_EMPTY
L1_fifo: FULL
L1_count: 16

L2_fifo: NOT_EMPTY
L2_fifo: FULL
L2_count: 10

L3_fifo: NOT_EMPTY
L3_fifo: FULL
L3_count: 16

ovf_l1: NOT_OVERFLOW
ovf_l3: NOT_OVERFLOW
udf_l1: NOT_UNDERFLOW
udf_l3: NOT_UNDERFLOW


E (17174) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
E (17174) task_wdt:  - IDLE (CPU 0)
E (17174) task_wdt: Tasks currently running:
E (17174) task_wdt: CPU 0: main
E (17174) task_wdt: CPU 1: IDLE
E (17174) task_wdt: Print CPU 0 (current core) backtrace


Backtrace:0x42008686:0x3FC95F400x4037A78A:0x3FC95F60 0x42005F7C:0x3FCF48C0 0x42005969:0x3FCF48E0 0x420054F5:0x3FCF4900 0x420179A1:0x3FCF4940 0x4037FEF1:0x3FCF4960 
0x42008686: task_wdt_isr at C:/esp-idf/components/esp_system/task_wdt.c:183 (discriminator 3)

0x4037a78a: _xt_lowint1 at C:/esp-idf/components/freertos/port/xtensa/xtensa_vectors.S:1111

0x42005f7c: hw_lcd_dma_tx_push_n_data at C:\esp32Projects\WSS_SERVER_AND_UI_INTEGRATION_S3\build/../components/ui/drv/src/hw_lcd_dma.c:720 (discriminator 4)

0x42005969: hw_lcd_write_n_data at C:\esp32Projects\WSS_SERVER_AND_UI_INTEGRATION_S3\build/../components/ui/drv/src/hw_lcd.c:635

0x420054f5: app_main at C:\esp32Projects\WSS_SERVER_AND_UI_INTEGRATION_S3\build/../main/src/main.c:84 (discriminator 1)

0x420179a1: main_task at C:/esp-idf/components/freertos/port/port_common.c:129 (discriminator 2)

0x4037fef1: vPortTaskWrapper at C:/esp-idf/components/freertos/port/xtensa/port.c:130


E (17174) task_wdt: Print CPU 1 backtrace


Backtrace:0x4037BD7D:0x3FC965400x4037A78A:0x3FC96560 0x400559DD:0x3FCF5900  |<-CORRUPTED
0x4037bd7d: esp_crosscore_isr at C:/esp-idf/components/esp_system/crosscore_int.c:92

0x4037a78a: _xt_lowint1 at C:/esp-idf/components/freertos/port/xtensa/xtensa_vectors.S:1111
Last edited by Baldhead on Mon Dec 27, 2021 3:37 am, edited 1 time in total.

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

Re: ESP32-S3 LCD and I2S FULL documentation

Postby ESP_Sprite » Mon Dec 27, 2021 2:35 am

Btw:
Why "GDMA.channel[channel].out.push.outfifo_wdata" is 9 bit wide ?
Got a response from the digital team: The 9th bit is the EOF bit. Setting this generates a DMA EOF interrupt when the byte is processed.

Baldhead
Posts: 468
Joined: Sun Mar 31, 2019 5:16 am

Re: ESP32-S3 LCD and I2S FULL documentation

Postby Baldhead » Mon Dec 27, 2021 3:05 am

@ESP_Sprite,

The strange thing is that "GDMA.channel[channel].out.int_raw.outfifo_ovf_l1" bit is not overflowing.

gdma_struct.h
uint32_t outfifo_ovf_l1: 1; /*This raw interrupt bit turns to high level when level 1 fifo of Tx channel 0 is overflow. */

Code: Select all

inline void hw_lcd_dma_tx_push_n_data( uint32_t channel, uint8_t* data, uint32_t data_len )
{ 
    printf("\x1b[31m");  // Red text

    printf("dma tx idle: %s\n", hw_lcd_dma_tx_idle(0) ? "IDLE" : "BUSY" );
    
    printf("L1_fifo: %s\n", hw_lcd_dma_L1_fifo_empty(0) ? "EMPTY" : "NOT_EMPTY" );
    printf("L1_fifo: %s\n", hw_lcd_dma_L1_fifo_full(0) ?  "FULL" : "NOT_FULL" );
    printf("L1_count: %u\n\n", hw_lcd_dma_L1_fifo_count(0) );

    printf("L2_fifo: %s\n", hw_lcd_dma_L2_fifo_empty(0) ? "EMPTY" : "NOT_EMPTY" );
    printf("L2_fifo: %s\n", hw_lcd_dma_L2_fifo_full(0) ?  "FULL" : "NOT_FULL" );
    printf("L2_count: %u\n\n", hw_lcd_dma_L2_fifo_count(0) );

    printf("L3_fifo: %s\n", hw_lcd_dma_L3_fifo_empty(0) ? "EMPTY" : "NOT_EMPTY" );
    printf("L3_fifo: %s\n", hw_lcd_dma_L3_fifo_full(0) ?  "FULL" : "NOT_FULL" );
    printf("L3_count: %u\n\n", hw_lcd_dma_L3_fifo_count(0) );

    printf("ovf_l1: %s\n", GDMA.channel[channel].out.int_raw.outfifo_ovf_l1 ? "OVERFLOW" : "NOT_OVERFLOW" );
    printf("ovf_l3: %s\n", GDMA.channel[channel].out.int_raw.outfifo_ovf_l3 ? "OVERFLOW" : "NOT_OVERFLOW" );

    printf("udf_l1: %s\n", GDMA.channel[channel].out.int_raw.outfifo_udf_l1 ? "UNDERLOW" : "NOT_UNDERFLOW" );
    printf("udf_l3: %s\n\n\n", GDMA.channel[channel].out.int_raw.outfifo_udf_l3 ? "UNDERLOW" : "NOT_UNDERFLOW" );


    for( uint32_t i = 0 ; i < data_len ; i++ )
    {       
        // while( hw_lcd_dma_L1_fifo_full(channel) );

        GDMA.channel[channel].out.push.outfifo_wdata = data[i];  // This register stores the data that need to be pushed into DMA FIFO.
        GDMA.channel[channel].out.push.outfifo_push = 1;         // Set this bit to push data into DMA FIFO.           
    }

    printf("\x1b[34m");  // blue text

    printf("dma tx idle: %s\n", hw_lcd_dma_tx_idle(0) ? "IDLE" : "BUSY" );
    
    printf("L1_fifo: %s\n", hw_lcd_dma_L1_fifo_empty(0) ? "EMPTY" : "NOT_EMPTY" );
    printf("L1_fifo: %s\n", hw_lcd_dma_L1_fifo_full(0) ?  "FULL" : "NOT_FULL" );
    printf("L1_count: %u\n\n", hw_lcd_dma_L1_fifo_count(0) );

    printf("L2_fifo: %s\n", hw_lcd_dma_L2_fifo_empty(0) ? "EMPTY" : "NOT_EMPTY" );
    printf("L2_fifo: %s\n", hw_lcd_dma_L2_fifo_full(0) ?  "FULL" : "NOT_FULL" );
    printf("L2_count: %u\n\n", hw_lcd_dma_L2_fifo_count(0) );

    printf("L3_fifo: %s\n", hw_lcd_dma_L3_fifo_empty(0) ? "EMPTY" : "NOT_EMPTY" );
    printf("L3_fifo: %s\n", hw_lcd_dma_L3_fifo_full(0) ?  "FULL" : "NOT_FULL" );
    printf("L3_count: %u\n\n", hw_lcd_dma_L3_fifo_count(0) );

    printf("ovf_l1: %s\n", GDMA.channel[channel].out.int_raw.outfifo_ovf_l1 ? "OVERFLOW" : "NOT_OVERFLOW" );
    printf("ovf_l3: %s\n", GDMA.channel[channel].out.int_raw.outfifo_ovf_l3 ? "OVERFLOW" : "NOT_OVERFLOW" );

    printf("udf_l1: %s\n", GDMA.channel[channel].out.int_raw.outfifo_udf_l1 ? "UNDERLOW" : "NOT_UNDERFLOW" );
    printf("udf_l3: %s\n\n\n", GDMA.channel[channel].out.int_raw.outfifo_udf_l3 ? "UNDERLOW" : "NOT_UNDERFLOW" ); 


    if( GDMA.channel[channel].out.int_raw.outfifo_ovf_l1 )
        while(1);
}

Who is online

Users browsing this forum: No registered users and 11 guests