I'm trying to port u8g2 library to ESP-32 while keeping interface the same. Current part is SPI driver.
I form a buffer from incoming bytes, then send it using DMA but something seems off and display show some messed up picture (but it is still possible to say that there is one).
I'm actually lost with possible mistakes. Are there any specific situations where just sending an array of bytes does not work as intended? While there are full bytes, they don't always form 32bit blocks. Is there anything special about such non-32bit complete blocks? What are other ways I can screw up SPI a little but not too much?
Thank you.
SPI DMA gotchas
Re: SPI DMA gotchas
Here's my problematic code:
And here is how il looks like whe I draw full-screen white box (each change is complete frame draw): https://youtu.be/Vzd91BQ8rZw
UPD: longer video https://youtu.be/K7tfP_Z6994
Code: Select all
static const spi_host_device_t u8x8_spibuses[2] = {HSPI_HOST, VSPI_HOST};
static uint8_t u8x8_byte_espidf_hw_spi_universal(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr, uint8_t host)
// It can work with any of two SPIs
{
u8x8_device_info* info = u8x8->user_ptr;
switch (msg) {
case U8X8_MSG_BYTE_SEND:
;
// We add stuff into buffer and then send it in one transaction
//if (info->spi.bufsiz != 0)
// hexDump("Old buf", info->spi.buffer, info->spi.bufsiz);
size_t oldsize = info->spi.bufsiz;
info->spi.bufsiz += arg_int;
//hexDump("Appending", arg_ptr, arg_int);
info->spi.buffer = heap_caps_realloc(info->spi.buffer, info->spi.bufsiz, MALLOC_CAP_DMA);
memcpy(info->spi.buffer + oldsize, arg_ptr, arg_int);
//hexDump("New buf", info->spi.buffer, info->spi.bufsiz);
break;
case U8X8_MSG_BYTE_INIT:
;
info->type = SPI;
info->spi.device = NULL;
info->spi.buffer = NULL;
info->spi.bufsiz = 0;
spi_bus_config_t busconf = {};
busconf.mosi_io_num = u8x8->pins[U8X8_PIN_SPI_DATA];
busconf.miso_io_num = -1;
busconf.sclk_io_num = u8x8->pins[U8X8_PIN_SPI_CLOCK];
busconf.quadwp_io_num = -1;
busconf.quadhd_io_num = -1;
busconf.max_transfer_sz = 0; // FIXME: add it into config
busconf.flags = 0; // FIXME: add stuff here?
if (u8x8->bus_clock == 0) { /* issue 769 */
u8x8->bus_clock = u8x8->display_info->sck_clock_hz;
}
/* disable chipselect */
//u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_disable_level);
spi_bus_initialize(u8x8_spibuses[host], &busconf, host + 1); // NOTE: user can set up it manually
spi_device_interface_config_t conf = {};
conf.command_bits = 0;
conf.address_bits = 0;
conf.dummy_bits = 0; // FIXME: Hmmm, may cause problems?
conf.mode = u8x8->display_info->spi_mode;
conf.duty_cycle_pos = 0; // I'm not sure
conf.clock_speed_hz = u8x8->bus_clock;
conf.input_delay_ns = 0;
conf.spics_io_num = u8x8->pins[U8X8_PIN_CS];
conf.flags = SPI_DEVICE_NO_DUMMY;
if (u8x8->display_info->chip_enable_level) {
conf.flags |= SPI_DEVICE_POSITIVE_CS;
}
conf.queue_size = 1; // I only use polling transactions, but ok
ESP_ERROR_CHECK(spi_bus_add_device(u8x8_spibuses[host], &conf, & (info->spi.device))); // FIXME: remove in destructor
break;
case U8X8_MSG_BYTE_SET_DC:
u8x8_gpio_SetDC(u8x8, arg_int);
break;
case U8X8_MSG_BYTE_START_TRANSFER:
// Nothing to do here
break;
case U8X8_MSG_BYTE_END_TRANSFER:
;
// Docs says that it's better to have 32-bit aligned memory
// Doing it here should make stuff faster
info->spi.buffer = heap_caps_realloc(info->spi.buffer, info->spi.bufsiz, MALLOC_CAP_DMA | MALLOC_CAP_32BIT);
/*
size_t incomplete_len = info->spi.bufsiz % 4U;
if (incomplete_len > 0) {
uint32_t* lastbyte = (uint32_t*)(info->spi.buffer - incomplete_len);
*lastbyte = SPI_SWAP_DATA_TX(*lastbyte, incomplete_len*8);
ESP_LOGI("u8x8", "Hi there! Size: %u, mistake: %u", info->spi.bufsiz, incomplete_len);
}
*/
spi_transaction_t transaction = {};
transaction.flags = 0;
transaction.length = (info->spi.bufsiz) * 8; // Bits
transaction.tx_buffer = info->spi.buffer;
transaction.rx_buffer = NULL; // U8g2 don't care about feedback, bad guys!
spi_device_polling_transmit(info->spi.device, &transaction);
heap_caps_free(info->spi.buffer);
info->spi.buffer = NULL;
info->spi.bufsiz = 0;
break;
default:
return 0;
}
return 1;
}
UPD: longer video https://youtu.be/K7tfP_Z6994
Re: SPI DMA gotchas
Well, problem lies outside of SPI: in DC line. Turned out that I have to flush data before every DC change.
Everything is working fine now . If somebody is wondering, you can find working code in https://github.com/v1993/u8g2/blob/mast ... /U8x8lib.c.
Everything is working fine now . If somebody is wondering, you can find working code in https://github.com/v1993/u8g2/blob/mast ... /U8x8lib.c.
Who is online
Users browsing this forum: No registered users and 96 guests