diff --git a/components/display/SH1106.c b/components/display/SH1106.c index a08a3116..c7d2da2e 100644 --- a/components/display/SH1106.c +++ b/components/display/SH1106.c @@ -140,6 +140,7 @@ static const struct GDS_Device SH1106 = { .SetLayout = SetLayout, .Update = Update, .Init = Init, .Depth = 1, + .CS_post = 2, #if !defined SHADOW_BUFFER && defined USE_IRAM .Alloc = GDS_ALLOC_IRAM_SPI; #endif diff --git a/components/display/core/gds_private.h b/components/display/core/gds_private.h index bec6a3c0..db0339b4 100644 --- a/components/display/core/gds_private.h +++ b/components/display/core/gds_private.h @@ -86,6 +86,7 @@ struct GDS_Device { struct { spi_device_handle_t SPIHandle; int8_t CSPin; + int8_t CS_pre, CS_post, SPI_mode; }; }; diff --git a/components/display/core/ifaces/default_if_spi.c b/components/display/core/ifaces/default_if_spi.c index ce0cd948..8c2c503d 100644 --- a/components/display/core/ifaces/default_if_spi.c +++ b/components/display/core/ifaces/default_if_spi.c @@ -51,6 +51,9 @@ bool GDS_SPIAttachDevice( struct GDS_Device* Device, int Width, int Height, int SPIDeviceConfig.spics_io_num = CSPin; SPIDeviceConfig.queue_size = 1; SPIDeviceConfig.flags = SPI_DEVICE_NO_DUMMY; + SPIDeviceConfig.cs_ena_pretrans = Device->CS_pre; + SPIDeviceConfig.cs_ena_posttrans = Device->CS_post; + SPIDeviceConfig.mode = Device->SPI_mode; ESP_ERROR_CHECK_NONFATAL( spi_bus_add_device( SPIHost, &SPIDeviceConfig, &SPIDevice ), return false ); @@ -74,16 +77,23 @@ bool GDS_SPIAttachDevice( struct GDS_Device* Device, int Width, int Height, int } static bool SPIDefaultWriteBytes( spi_device_handle_t SPIHandle, int WriteMode, const uint8_t* Data, size_t DataLength ) { - spi_transaction_t SPITransaction = { 0 }; + spi_transaction_t SPITransaction = { }; NullCheck( SPIHandle, return false ); NullCheck( Data, return false ); if ( DataLength > 0 ) { gpio_set_level( DCPin, WriteMode ); - + SPITransaction.length = DataLength * 8; - SPITransaction.tx_buffer = Data; + + if (DataLength <= 4) { + SPITransaction.flags = SPI_TRANS_USE_TXDATA; + SPITransaction.tx_data[0] = *Data++; SPITransaction.tx_data[1] = *Data++; + SPITransaction.tx_data[2] = *Data++; SPITransaction.tx_data[3] = *Data; + } else { + SPITransaction.tx_buffer = Data; + } // only do polling as we don't have contention on SPI (otherwise DMA for transfers > 16 bytes) ESP_ERROR_CHECK_NONFATAL( spi_device_polling_transmit(SPIHandle, &SPITransaction), return false ); diff --git a/components/services/gpio_exp.c b/components/services/gpio_exp.c index a2ac0582..e0628ab1 100644 --- a/components/services/gpio_exp.c +++ b/components/services/gpio_exp.c @@ -99,23 +99,23 @@ static const struct gpio_exp_model_s { void (*set_pull_mode)(gpio_exp_t* self); } registered[] = { { .model = "pca9535", - .trigger = GPIO_INTR_NEGEDGE, + .trigger = GPIO_INTR_LOW_LEVEL, .set_direction = pca9535_set_direction, .read = pca9535_read, .write = pca9535_write, }, { .model = "pca85xx", - .trigger = GPIO_INTR_NEGEDGE, + .trigger = GPIO_INTR_LOW_LEVEL, .read = pca85xx_read, .write = pca85xx_write, }, { .model = "mcp23017", - .trigger = GPIO_INTR_NEGEDGE, + .trigger = GPIO_INTR_LOW_LEVEL, .init = mcp23017_init, .set_direction = mcp23017_set_direction, .set_pull_mode = mcp23017_set_pull_mode, .read = mcp23017_read, .write = mcp23017_write, }, { .model = "mcp23s17", - .trigger = GPIO_INTR_NEGEDGE, + .trigger = GPIO_INTR_LOW_LEVEL, .init = mcp23s17_init, .set_direction = mcp23s17_set_direction, .set_pull_mode = mcp23s17_set_pull_mode, @@ -406,6 +406,9 @@ static void IRAM_ATTR intr_isr_handler(void* arg) { gpio_exp_t *self = (gpio_exp_t*) arg; BaseType_t woken = pdFALSE; + // edge interrupts do not work because of read/clear = potential short pulse + gpio_intr_disable(self->intr); + // activate all, including ourselves for (int i = 0; i < n_expanders; i++) if (expanders[i].intr == self->intr) expanders[i].intr_pending = true; @@ -439,26 +442,22 @@ void service_handler(void *arg) { for (int i = 0; i < n_expanders; i++) { gpio_exp_t *expander = expanders + i; - // no interrupt for that gpio - if (expander->intr < 0) continue; + // no interrupt for that gpio or not pending (safe as interrupt is disabled) + if (expander->intr < 0 || !expander->intr_pending) continue; - // only check expander with pending interrupts - gpio_intr_disable(expander->intr); - if (!expander->intr_pending) { - gpio_intr_enable(expander->intr); - continue; - } - expander->intr_pending = false; - gpio_intr_enable(expander->intr); - xSemaphoreTake(expander->mutex, pdMS_TO_TICKS(50)); // read GPIOs and clear all pending status uint32_t value = expander->model->read(expander); + expander->age = xTaskGetTickCount(); + + // re-enable interrupt now that it has been cleared + expander->intr_pending = false; + gpio_intr_enable(expander->intr); + uint32_t pending = expander->pending | ((expander->shadow ^ value) & expander->r_mask); expander->shadow = value; expander->pending = 0; - expander->age = xTaskGetTickCount(); xSemaphoreGive(expander->mutex); ESP_LOGD(TAG, "Handling GPIO %d reads 0x%04x and has 0x%04x pending", expander->first, expander->shadow, pending); @@ -468,7 +467,7 @@ void service_handler(void *arg) { gpio -= clz; if (expander->isr[gpio].timer) xTimerReset(expander->isr[gpio].timer, 1); // todo 0 else if (expander->isr[gpio].handler) expander->isr[gpio].handler(expander->isr[gpio].arg); - } + } } }