0

I use the following code to communicate with a display:

void Display_HandleDC(spi_transaction_t* p_Transaction)
{
    gpio_set_level((gpio_num_t)LCD_DC, (uint32_t)p_Transaction->user);
}

static void Display_SendCommand(const uint8_t Command)
{
    spi_transaction_t t;

    memset(&t, 0, sizeof(t));

    t.length = 8;
    t.tx_buffer = &Command;
    t.user=(void*)0;

    assert(spi_device_polling_transmit(_SPI, &t) == ESP_OK);
}

static void Display_SendData(const uint8_t* p_Data, uint32_t Length)
{
    spi_transaction_t t;

    if(Length == 0)
    {
        return;
    }

    memset(&t, 0, sizeof(t));

    t.length = Length * 8;
    t.tx_buffer = p_Data;
    t.user=(void*)1;

    assert(spi_device_polling_transmit(_SPI, &t) == ESP_OK);
}

static uint32_t Display_ReadID(void)
{
    spi_transaction_t t;

    Display_SendCommand(0x04);

    memset(&t, 0, sizeof(t));
    t.length = 4 * 8;
    t.flags = SPI_TRANS_USE_RXDATA;
    t.user = (void*)1;

    assert(spi_device_polling_transmit(_SPI, &t) == ESP_OK);

    return *(uint32_t*)t.rx_data;
}

static void Display_Write(int ypos, uint16_t *linedata)
{
    static spi_transaction_t trans[6];

    for(uint8_t x=0; x<6; x++)
    {
        memset(&trans[x], 0, sizeof(spi_transaction_t));
        if ((x&1)==0) {
            //Even transfers are commands
            trans[x].length=8;
            trans[x].user=(void*)0;
        } else {
            //Odd transfers are data
            trans[x].length=8*4;
            trans[x].user=(void*)1;
        }

        trans[x].flags = SPI_TRANS_USE_TXDATA;
    }

    trans[0].tx_data[0] = 0x2A;
    trans[1].tx_data[0] = 0;
    trans[1].tx_data[1] = 0;
    trans[1].tx_data[2] = 320 >> 8;
    trans[1].tx_data[3] = 320 & 0xFF;

    trans[2].tx_data[0] = 0x2B;
    trans[3].tx_data[0] = ypos >> 8;
    trans[3].tx_data[1] = ypos & 0xFF;
    trans[3].tx_data[2] = (ypos + 1) >> 8;
    trans[3].tx_data[3] = (ypos + 1) & 0xFF;

    // Write the data to memory
    trans[4].tx_data[0] = 0x2C;
    trans[5].tx_buffer = linedata;
    trans[5].length = 320 * sizeof(uint16_t) * 8;
    trans[5].flags = 0x00;

    for(uint8_t x = 0; x<6; x++)
    {
        assert(spi_device_queue_trans(_SPI, &trans[x], portMAX_DELAY) == ESP_OK);
    }
}

static void Display_Busy(void)
{
    spi_transaction_t* rtrans;
    for(uint8_t x=0; x<6; x++)
    {
        assert(spi_device_get_trans_result(_SPI, &rtrans, portMAX_DELAY) == ESP_OK);
    }
}

esp_err_t Display_Init(void)
{
    static uint16_t* Line;

    gpio_set_direction((gpio_num_t)LCD_DC, GPIO_MODE_OUTPUT);
    gpio_set_direction((gpio_num_t)LDC_RESET, GPIO_MODE_OUTPUT);
    gpio_set_direction((gpio_num_t)LCD_BACKLIGHT, GPIO_MODE_OUTPUT);

    if((spi_bus_initialize(HSPI_HOST, &_BusCfg, 0) != ESP_OK) || (spi_bus_add_device(HSPI_HOST, &_DevDcfg, &_SPI) != ESP_OK))
    {
        return ESP_FAIL;
    }

    Display_Reset();
    ESP_LOGI(TAG, "ID: %08X", Display_ReadID());

    uint32_t Commands = sizeof(_Init_Cmd_List) / sizeof(_Init_Cmd_List[0]);
    ESP_LOGI(TAG, "Loading initialization commands: %u", Commands);

    for(uint32_t i = 0x00; i < Commands; i++)
    {
        ESP_LOGI(TAG, "     Command %u / %u", i + 1, Commands);
        Display_SendCommand(_Init_Cmd_List[i].Command);
        Display_SendData(_Init_Cmd_List[i].Data, _Init_Cmd_List[i].Length & 0x1F);
        if(_Init_Cmd_List[i].Length & 0x80)
        {
            vTaskDelay(100 / portTICK_RATE_MS);
        }
    }

    Line = (uint16_t*)heap_caps_malloc(320 * sizeof(uint16_t), MALLOC_CAP_DMA);
    if(Line == NULL)
    {
        return ESP_FAIL;
    }

    for(uint32_t i = 0x00; i < 320; i++)
    {
        Line[i] = 0xF8;
    }

    Display_Write(0, Line);
    Display_Busy();
    free(Line);

    return ESP_OK;
}

And this code results in the following error message:

E (1833) spi_master: check_trans_valid(801): txdata transfer > host maximum
assertion "spi_device_queue_trans(_SPI, &trans[x], portMAX_DELAY) == ESP_OK" failed: file "src/Peripherals/Display/display.cpp", line 225, function: void Display_Write(int, uint16_t*)
abort() was called at PC 0x400e47a4 on core 1

ELF file SHA256: bc86d952445723b2

Backtrace: 0x4008e8c0:0x3ffb4b30 0x4008ecb9:0x3ffb4b50 0x400e47a4:0x3ffb4b70 0x400d170d:0x3ffb4ba0 0x400d1873:0x3ffb4bc0 0x400d13ea:0x3ffb4bf0 0x400d194b:0x3ffb4c20 0x40088601:0x3ffb4c40
  #0  0x4008e8c0:0x3ffb4b30 in invoke_abort at .platformio\packages\framework-espidf@3.40001.200521\components\esp32/panic.c:155
  #1  0x4008ecb9:0x3ffb4b50 in abort at .platformio\packages\framework-espidf@3.40001.200521\components\esp32/panic.c:172
  #2  0x400e47a4:0x3ffb4b70 in __assert_func at /builds/idf/crosstool-NG/.build/HOST-i686-w64-mingw32/xtensa-esp32-elf/src/newlib/newlib/libc/stdlib/assert.c:62 (discriminator 8)  
  #3  0x400d170d:0x3ffb4ba0 in Display_Write(int, unsigned short*) at src/Peripherals/Display/display.cpp:225 (discriminator 1)
  #4  0x400d1873:0x3ffb4bc0 in Display_Init() at src/Peripherals/Display/display.cpp:288
  #5  0x400d13ea:0x3ffb4bf0 in setup() at src/Application/application.cpp:21
  #6  0x400d194b:0x3ffb4c20 in applicationTask(void*) at src/main.cpp:41
  #7  0x40088601:0x3ffb4c40 in vPortTaskWrapper at .platformio\packages\framework-espidf@3.40001.200521\components\freertos/port.c:143

But the error doesn´t occur when I change the DMA channel from 0 to 1:

if((spi_bus_initialize(HSPI_HOST, &_BusCfg, 1) != ESP_OK) || (spi_bus_add_device(HSPI_HOST, &_DevDcfg, &_SPI) != ESP_OK))
{
    return ESP_FAIL;
}

What´s the difference between both channels and why is only channel 1 working?

0

1 Answer 1

1

Your code initializes the SPI bus by calling the spi_bus_initialize(HSPI_HOST, &_BusCfg, 0) function. The last argument of this function (int dma_chan) defines the DMA channel to use, which can be 0, 1 or 2.

Selecting DMA channel "0" will actually not select a DMA channel at all (which is explained in the Espressif documentation):

  • dma_chan: Either channel 1 or 2, or 0 in the case when no DMA is required. Selecting a DMA channel for a SPI bus allows transfers on the bus to have sizes only limited by the amount of internal memory. Selecting no DMA channel (by passing the value 0) limits the amount of bytes transfered to a maximum of 32.

The reason you get an error when your ESP32 tries to do an SPI transfer when no DMA channel is selected (option 0), is that the transfer apparently is larger than 32 bytes.

The error produced is "E (1833) spi_master: check_trans_valid(801): txdata transfer > host maximum", which reflects that.

The reason DMA channel 1 works correctly, is because that is an actual DMA channel and it has no limit on the amount of bytes transferred (only limited by the amount of internal memory).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.